Skip to content

Commit

Permalink
'tidied localStorage'
Browse files Browse the repository at this point in the history
  • Loading branch information
neocotic committed Mar 14, 2012
1 parent 4b8d217 commit 05b5b13
Showing 1 changed file with 115 additions and 44 deletions.
159 changes: 115 additions & 44 deletions lib/oauth2.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ var OAuth2 = function(adapterName, config) {
that.adapter = OAuth2.adapters[adapterName];
if (config == OAuth2.FINISH) {
that.finishAuth();
return;
} else if (config) {
that.set('clientId', config.client_id);
that.set('clientSecret', config.client_secret);
that.set('apiScope', config.api_scope);
that.updateLocalStorage();

var data = that.get();
data.clientId = config.client_id;
data.clientSecret = config.client_secret;
data.apiScope = config.api_scope;
that.source(data);
}
});
};
Expand All @@ -47,8 +50,42 @@ OAuth2.FINISH = 'finish';
* OAuth 2.0 endpoint adapters known to the library
*/
OAuth2.adapters = {};
OAuth2.adapterReverse = localStorage.adapterReverse &&
JSON.parse(localStorage.adapterReverse) || {};
OAuth2.adapterReverse = localStorage.oauth2_adapterReverse &&
JSON.parse(localStorage.oauth2_adapterReverse) || {};
// Update the persisted adapterReverse in localStorage.
if (localStorage.adapterReverse) {
OAuth2.adapterReverse = JSON.parse(localStorage.adapterReverse);
delete localStorage.adapterReverse;
}

/**
* Consolidates the data stored in localStorage on the current adapter in to
* a single JSON object.
* The update should only ever happen once per adapter and will delete the old
* obsolete entries in localStorage after copying their values.
*/
OAuth2.prototype.updateLocalStorage = function() {
// Check if update is even required.
if (this.source()) {
return;
}
var data = {};
var variables = [
'accessToken', 'accessTokenDate', 'apiScope', 'clientId', 'clientSecret',
'expiresIn', 'refreshToken'
];
// Check if a variable has already been persisted and then copy them.
var key;
for (var i = 0; i < variables.length; i++) {
key = this.adapterName + '_' + variables[i];
if (localStorage.hasOwnProperty(key)) {
data[variables[i]] = localStorage[key];
delete localStorage[key];
}
}
// Persist the new JSON object in localStorage.
this.source(data);
};

/**
* Opens up an authorization popup window. This starts the OAuth 2.0 flow.
Expand Down Expand Up @@ -143,9 +180,10 @@ OAuth2.prototype.refreshAccessToken = function(refreshToken, callback) {
}
};

var data = this.get();
var formData = new FormData();
formData.append('client_id', this.get('clientId'));
formData.append('client_secret', this.get('clientSecret'));
formData.append('client_id', data.clientId);
formData.append('client_secret', data.clientSecret);
formData.append('refresh_token', refreshToken);
formData.append('grant_type', 'refresh_token');
xhr.open('POST', this.adapter.accessTokenURL(), true);
Expand Down Expand Up @@ -188,13 +226,15 @@ OAuth2.prototype.finishAuth = function() {
}

that.getAccessAndRefreshTokens(authorizationCode, function(at, rt, exp) {
that.set('accessTokenDate', (new Date()).valueOf());
that.set('accessToken', at);
that.set('expiresIn', exp);
var data = that.get();
data.accessTokenDate = new Date().valueOf();
data.accessToken = at;
data.expiresIn = exp;
// Most OAuth 2.0 providers don't have a refresh token
if (rt) {
that.set('refreshToken', rt);
data.refreshToken = rt;
}
that.source(data);

callback();
});
Expand All @@ -204,52 +244,80 @@ OAuth2.prototype.finishAuth = function() {
* @return True iff the current access token has expired
*/
OAuth2.prototype.isAccessTokenExpired = function() {
return (new Date().valueOf() - this.get('accessTokenDate')) >
this.get('expiresIn') * 1000;
var data = this.get();
return (new Date().valueOf() - data.accessTokenDate) > data.expiresIn * 1000;
};

/**
* Wrapper around the localStorage object that gets variables prefixed
* by the adapter name
* Get the persisted adapter data in localStorage. Optionally, provide a
* property name to only retrieve its value.
*
* @param {String} key The key to use for lookup
* @return {String} The value
* @param {String} [name] The name of the property to be retrieved.
* @return The data object or property value if name was specified.
*/
OAuth2.prototype.get = function(key) {
return localStorage[this.adapterName + '_' + key];
OAuth2.prototype.get = function(name) {
var src = this.source();
var obj = src ? JSON.parse(src) : {};
return name ? obj[name] : obj;
};

/**
* Wrapper around the localStorage object that sets variables prefixed
* by the adapter name
* Set the value of a named property on the persisted adapter data in
* localStorage.
*
* @param {String} key The key to store with
* @param {String} value The value to store
* @param {String} name The name of the property to change.
* @param value The value to be set.
*/
OAuth2.prototype.set = function(key, value) {
localStorage[this.adapterName + '_' + key] = value;
OAuth2.prototype.set = function(name, value) {
var obj = this.get();
obj[name] = value;
this.source(obj);
};

/**
* Wrapper around the localStorage object that clears values prefixed by the
* adapter name
* Clear all persisted adapter data in localStorage. Optionally, provide a
* property name to only clear its value.
*
* @param {String} key The key to clear from localStorage
* @param {String} [name] The name of the property to clear.
*/
OAuth2.prototype.clear = function(key) {
delete localStorage[this.adapterName + '_' + key];
OAuth2.prototype.clear = function(name) {
if (name) {
var obj = this.get();
delete obj[name];
this.source(obj);
} else {
delete localStorage['oauth2_' + this.adapterName];
}
};

/**
* Get the JSON string for the object stored in localStorage. Optionally,
* provide a new string to be persisted.
*
* @param {String} [source] The new JSON string to be set.
* @return {String} The source JSON string after any possible changes.
*/
OAuth2.prototype.source = function(source) {
if (source) {
if (typeof source !== 'string') {
source = JSON.stringify(source);
}
localStorage['oauth2_' + this.adapterName] = source;
}
return localStorage['oauth2_' + this.adapterName];
};

/**
* The configuration parameters that are passed to the adapter
* Get the configuration parameters to be passed to the adapter.
*
* @returns {Object} Containing clientId, clientSecret and apiScope
* @returns {Object} Contains clientId, clientSecret and apiScope.
*/
OAuth2.prototype.getConfig = function() {
var data = this.get();
return {
clientId: this.get('clientId'),
clientSecret: this.get('clientSecret'),
apiScope: this.get('apiScope')
clientId: data.clientId,
clientSecret: data.clientSecret,
apiScope: data.apiScope
};
};

Expand Down Expand Up @@ -305,7 +373,7 @@ OAuth2.adapter = function(name, impl) {
// Make an entry in the adapter lookup table
OAuth2.adapterReverse[impl.redirectURL()] = name;
// Store the the adapter lookup table in localStorage
localStorage.adapterReverse = JSON.stringify(OAuth2.adapterReverse);
localStorage.oauth2_adapterReverse = JSON.stringify(OAuth2.adapterReverse);
};

/**
Expand All @@ -316,7 +384,7 @@ OAuth2.adapter = function(name, impl) {
* @return The adapter for the current page
*/
OAuth2.lookupAdapterName = function(url) {
var adapterReverse = JSON.parse(localStorage.adapterReverse);
var adapterReverse = JSON.parse(localStorage.oauth2_adapterReverse);
return adapterReverse[url];
};

Expand All @@ -336,16 +404,19 @@ OAuth2.prototype.authorize = function(callback) {
var that = this;
OAuth2.loadAdapter(that.adapterName, function() {
that.adapter = OAuth2.adapters[that.adapterName];
if (!that.get('accessToken')) {
var data = that.get();
if (!data.accessToken) {
// There's no access token yet. Start the authorizationCode flow
that.openAuthorizationCodePopup(callback);
} else if (that.isAccessTokenExpired()) {
// There's an existing access token but it's expired
if (that.get('refreshToken')) {
that.refreshAccessToken(that.get('refreshToken'), function(at, exp) {
that.set('accessToken', at);
that.set('expiresIn', exp);
that.set('accessTokenDate', (new Date()).valueOf());
if (data.refreshToken) {
that.refreshAccessToken(data.refreshToken, function(at, exp) {
var newData = that.get();
newData.accessTokenDate = new Date().valueOf();
newData.accessToken = at;
newData.expiresIn = exp;
that.source(newData);
// Callback when we finish refreshing
if (callback) {
callback();
Expand Down

0 comments on commit 05b5b13

Please sign in to comment.