1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-22 08:52:15 -05:00

Remove cached OAuth token before reconnect

This commit is contained in:
Tankred Hase 2014-08-05 16:44:39 +02:00
parent eb0002c8d5
commit c4337fba30
6 changed files with 136 additions and 13 deletions

View File

@ -13,7 +13,7 @@
"crypto-lib": "~0.2.1",
"imap-client": "~0.3.7",
"mailreader": "~0.3.5",
"pgpmailer": "~0.3.10",
"pgpmailer": "~0.3.11",
"pgpbuilder": "~0.3.7",
"requirejs": "2.1.14",
"axe-logger": "~0.0.2",

View File

@ -133,7 +133,8 @@ define(function(require) {
function initClients(credentials) {
var pgpMailer = new PgpMailer(credentials.smtp, self._pgpbuilder);
var imapClient = new ImapClient(credentials.imap);
imapClient.onError = onImapError;
imapClient.onError = onConnectionError;
pgpMailer.onError = onConnectionError;
// certificate update handling
imapClient.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'imap', self.onConnect, self.onError);
@ -151,19 +152,19 @@ define(function(require) {
}, callback);
}
function onImapError(error) {
axe.debug('IMAP connection error. Attempting reconnect in ' + config.reconnectInterval + ' ms. Error: ' + (error.errMsg || error.message) + (error.stack ? ('\n' + error.stack) : ''));
function onConnectionError(error) {
axe.debug('Connection error. Attempting reconnect in ' + config.reconnectInterval + ' ms. Error: ' + (error.errMsg || error.message) + (error.stack ? ('\n' + error.stack) : ''));
setTimeout(function() {
axe.debug('IMAP reconnecting...');
axe.debug('Reconnecting...');
// re-init client modules on error
self.onConnect(function(err) {
if (err) {
axe.error('IMAP reconnect attempt failed! ' + (err.errMsg || err.message) + (err.stack ? ('\n' + err.stack) : ''));
axe.error('Reconnect attempt failed! ' + (err.errMsg || err.message) + (err.stack ? ('\n' + err.stack) : ''));
return;
}
axe.debug('IMAP reconnect attempt complete.');
axe.debug('Reconnect attempt complete.');
});
}, config.reconnectInterval);
}

View File

@ -256,8 +256,18 @@ define(function(require) {
Auth.prototype.getOAuthToken = function(callback) {
var self = this;
// get a fresh oauth token
self._oauth.getOAuthToken(self.emailAddress, function(err, oauthToken) {
if (self.oauthToken) {
// removed cached token and get a new one
self._oauth.refreshToken({
emailAddress: self.emailAddress,
oldToken: self.oauthToken
}, onToken);
} else {
// get a fresh oauth token
self._oauth.getOAuthToken(self.emailAddress, onToken);
}
function onToken(err, oauthToken) {
if (err) {
return callback(err);
}
@ -278,7 +288,7 @@ define(function(require) {
self.emailAddress = emailAddress;
callback();
});
});
}
};
/**

View File

@ -5,12 +5,17 @@ define(function() {
this._googleApi = googleApi;
};
/**
* Check if chrome.identity api is supported
* @return {Boolean} If is supported
*/
OAuth.prototype.isSupported = function() {
return !!(window.chrome && chrome.identity);
};
/**
* Request an OAuth token from chrome for gmail users
* @param {String} emailAddress The user's email address (optional)
*/
OAuth.prototype.getOAuthToken = function(emailAddress, callback) {
var idOptions = {
@ -19,7 +24,7 @@ define(function() {
// check which runtime the app is running under
chrome.runtime.getPlatformInfo(function(platformInfo) {
if ((chrome && chrome.runtime && chrome.runtime.lastError) || !platformInfo) {
if (chrome.runtime.lastError || !platformInfo) {
callback(new Error('Error getting chrome platform info!'));
return;
}
@ -31,7 +36,7 @@ define(function() {
// get OAuth Token from chrome
chrome.identity.getAuthToken(idOptions, function(token) {
if ((chrome && chrome.runtime && chrome.runtime.lastError) || !token) {
if (chrome.runtime.lastError || !token) {
callback({
errMsg: 'Error fetching an OAuth token for the user!'
});
@ -43,6 +48,32 @@ define(function() {
});
};
/**
* Remove an old OAuth token and get a new one.
* @param {String} options.oldToken The old token to be removed
* @param {String} options.emailAddress The user's email address (optional)
*/
OAuth.prototype.refreshToken = function(options, callback) {
var self = this;
if (!options.oldToken) {
callback(new Error('oldToken option not set!'));
return;
}
// remove cached token
chrome.identity.removeCachedAuthToken({
token: options.oldToken
}, function() {
// get a new token
self.getOAuthToken(options.emailAddress, callback);
});
};
/**
* Get email address from google api
* @param {String} token The oauth token
*/
OAuth.prototype.queryEmailAddress = function(token, callback) {
if (!token) {
callback({

View File

@ -146,6 +146,26 @@ define(function(require) {
});
describe('#getOAuthToken', function() {
it('should refresh token with known email address', function(done) {
auth.emailAddress = emailAddress;
auth.oauthToken = 'oldToken';
oauthStub.refreshToken.withArgs({
emailAddress: emailAddress,
oldToken: 'oldToken'
}).yieldsAsync(null, oauthToken);
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.refreshToken.calledOnce).to.be.true;
done();
});
});
it('should fetch token with known email address', function(done) {
auth.emailAddress = emailAddress;
oauthStub.getOAuthToken.withArgs(emailAddress).yieldsAsync(null, oauthToken);

View File

@ -6,7 +6,7 @@ define(function(require) {
expect = chai.expect;
describe('OAuth unit tests', function() {
var oauth, googleApiStub, identityStub, getPlatformInfoStub,
var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub,
testEmail = 'test@example.com';
beforeEach(function() {
@ -21,6 +21,11 @@ define(function(require) {
}
identityStub = sinon.stub(window.chrome.identity, 'getAuthToken');
if (typeof window.chrome.identity.removeCachedAuthToken !== 'function') {
window.chrome.identity.removeCachedAuthToken = function() {};
}
removeCachedStub = sinon.stub(window.chrome.identity, 'removeCachedAuthToken');
window.chrome.runtime = window.chrome.runtime || {};
if (typeof window.chrome.runtime.getPlatformInfo !== 'function') {
window.chrome.runtime.getPlatformInfo = function() {};
@ -31,6 +36,7 @@ define(function(require) {
afterEach(function() {
identityStub.restore();
getPlatformInfoStub.restore();
removeCachedStub.restore();
});
describe('isSupported', function() {
@ -39,6 +45,61 @@ define(function(require) {
});
});
describe('refreshToken', function() {
var getOAuthTokenStub;
beforeEach(function() {
getOAuthTokenStub = sinon.stub(oauth, 'getOAuthToken');
});
afterEach(function() {
getOAuthTokenStub.restore();
});
it('should work', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
getOAuthTokenStub.withArgs(testEmail).yields();
oauth.refreshToken({
oldToken: 'oldToken',
emailAddress: testEmail
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
});
});
it('should work without email', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
getOAuthTokenStub.withArgs(undefined).yields();
oauth.refreshToken({
oldToken: 'oldToken',
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledWith(undefined)).to.be.true;
});
});
it('should fail without all options', function() {
oauth.refreshToken({
emailAddress: testEmail
}, function(err) {
expect(err).to.exist;
expect(removeCachedStub.called).to.be.false;
expect(getOAuthTokenStub.called).to.be.false;
});
});
});
describe('getOAuthToken', function() {
it('should work for empty emailAddress', function(done) {
getPlatformInfoStub.yields({