| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- /* eslint complexity:[0,8] max-statements:[0,21] */
- var util = require('./util');
- var AuthSdkError = require('./errors/AuthSdkError');
- var storageUtil = require('./storageUtil');
- var Q = require('q');
- var Emitter = require('tiny-emitter');
- var config = require('./config');
- var storageBuilder = require('./storageBuilder');
-
- function emitExpired(tokenMgmtRef, key, token) {
- tokenMgmtRef.emitter.emit('expired', key, token);
- }
-
- function clearRefreshTimeout(tokenMgmtRef, key) {
- clearTimeout(tokenMgmtRef.refreshTimeouts[key]);
- delete tokenMgmtRef.refreshTimeouts[key];
- }
-
- function clearRefreshTimeoutAll(tokenMgmtRef) {
- var refreshTimeouts = tokenMgmtRef.refreshTimeouts;
- for(var key in refreshTimeouts) {
- if (!refreshTimeouts.hasOwnProperty(key)) {
- continue;
- }
- clearRefreshTimeout(tokenMgmtRef, key);
- }
- tokenMgmtRef.refreshTimeouts = {};
- }
-
- function setRefreshTimeout(sdk, tokenMgmtRef, storage, key, token) {
- var refreshWait = (token.expiresAt * 1000) - Date.now();
- if (refreshWait < 0) {
- // Already expired
- refreshWait = 0;
- }
- var refreshTimeout = setTimeout(function() {
- if (tokenMgmtRef.autoRefresh) {
- return refresh(sdk, tokenMgmtRef, storage, key);
- } else if (token.expiresAt * 1000 <= Date.now()) {
- remove(tokenMgmtRef, storage, key);
- emitExpired(tokenMgmtRef, key, token);
- }
- }, refreshWait);
-
- // Clear any existing timeout
- clearRefreshTimeout(tokenMgmtRef, key);
-
- // Add a new timeout
- tokenMgmtRef.refreshTimeouts[key] = refreshTimeout;
- }
-
- function setRefreshTimeoutAll(sdk, tokenMgmtRef, storage) {
- try {
- var tokenStorage = storage.getStorage();
- } catch(e) {
- // Any errors thrown on instantiation will not be caught,
- // because there are no listeners yet
- tokenMgmtRef.emitter.emit('error', e);
- return;
- }
-
- for(var key in tokenStorage) {
- if (!tokenStorage.hasOwnProperty(key)) {
- continue;
- }
- var token = tokenStorage[key];
- setRefreshTimeout(sdk, tokenMgmtRef, storage, key, token);
- }
- }
-
- function add(sdk, tokenMgmtRef, storage, key, token) {
- var tokenStorage = storage.getStorage();
- if (!util.isObject(token) ||
- !token.scopes ||
- (!token.expiresAt && token.expiresAt !== 0) ||
- (!token.idToken && !token.accessToken)) {
- throw new AuthSdkError('Token must be an Object with scopes, expiresAt, and an idToken or accessToken properties');
- }
- tokenStorage[key] = token;
- storage.setStorage(tokenStorage);
- setRefreshTimeout(sdk, tokenMgmtRef, storage, key, token);
- }
-
- function get(storage, key) {
- var tokenStorage = storage.getStorage();
- return tokenStorage[key];
- }
-
- function remove(tokenMgmtRef, storage, key) {
- // Clear any listener for this token
- clearRefreshTimeout(tokenMgmtRef, key);
-
- // Remove it from storage
- var tokenStorage = storage.getStorage();
- delete tokenStorage[key];
- storage.setStorage(tokenStorage);
- }
-
- function refresh(sdk, tokenMgmtRef, storage, key) {
- try {
- var token = get(storage, key);
- if (!token) {
- throw new AuthSdkError('The tokenManager has no token for the key: ' + key);
- }
- } catch (e) {
- return Q.reject(e);
- }
-
- // Remove existing autoRefresh timeout for this key
- clearRefreshTimeout(tokenMgmtRef, key);
-
- return sdk.token.refresh(token)
- .then(function(freshToken) {
- add(sdk, tokenMgmtRef, storage, key, freshToken);
- tokenMgmtRef.emitter.emit('refreshed', key, freshToken, token);
- return freshToken;
- })
- .fail(function(err) {
- if (err.name === 'OAuthError') {
- remove(tokenMgmtRef, storage, key);
- emitExpired(tokenMgmtRef, key, token);
- }
- throw err;
- });
- }
-
- function clear(tokenMgmtRef, storage) {
- clearRefreshTimeoutAll(tokenMgmtRef);
- storage.clearStorage();
- }
-
- function TokenManager(sdk, options) {
- options = options || {};
- options.storage = options.storage || 'localStorage';
- if (!options.autoRefresh && options.autoRefresh !== false) {
- options.autoRefresh = true;
- }
-
- if (options.storage === 'localStorage' && !storageUtil.browserHasLocalStorage()) {
- util.warn('This browser doesn\'t support localStorage. Switching to sessionStorage.');
- options.storage = 'sessionStorage';
- }
-
- if (options.storage === 'sessionStorage' && !storageUtil.browserHasSessionStorage()) {
- util.warn('This browser doesn\'t support sessionStorage. Switching to cookie-based storage.');
- options.storage = 'cookie';
- }
-
- var storage;
- switch(options.storage) {
- case 'localStorage':
- storage = storageBuilder(localStorage, config.TOKEN_STORAGE_NAME);
- break;
- case 'sessionStorage':
- storage = storageBuilder(sessionStorage, config.TOKEN_STORAGE_NAME);
- break;
- case 'cookie':
- storage = storageBuilder(storageUtil.getCookieStorage(), config.TOKEN_STORAGE_NAME);
- break;
- default:
- throw new AuthSdkError('Unrecognized storage option');
- }
-
- var tokenMgmtRef = {
- emitter: new Emitter(),
- autoRefresh: options.autoRefresh,
- refreshTimeouts: {}
- };
-
- this.add = util.bind(add, this, sdk, tokenMgmtRef, storage);
- this.get = util.bind(get, this, storage);
- this.remove = util.bind(remove, this, tokenMgmtRef, storage);
- this.clear = util.bind(clear, this, tokenMgmtRef, storage);
- this.refresh = util.bind(refresh, this, sdk, tokenMgmtRef, storage);
- this.on = util.bind(tokenMgmtRef.emitter.on, tokenMgmtRef.emitter);
- this.off = util.bind(tokenMgmtRef.emitter.off, tokenMgmtRef.emitter);
-
- setRefreshTimeoutAll(sdk, tokenMgmtRef, storage);
- }
-
- module.exports = TokenManager;
|