UNPKG

@terminus/ngx-tools

Version:

[![CircleCI][circle-badge]][circle-link] [![codecov][codecov-badge]][codecov-project] [![semantic-release][semantic-release-badge]][semantic-release] [![MIT License][license-image]][license-url] <br> [![NPM version][npm-version-image]][npm-url] [![Github

964 lines (917 loc) 45.8 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@terminus/ngx-tools/utilities'), require('@angular/core'), require('@ngrx/effects'), require('@ngrx/store'), require('@terminus/ngx-tools/browser'), require('rxjs'), require('rxjs/internal/scheduler/async'), require('rxjs/operators'), require('@angular/common/http'), require('@terminus/ngx-tools/type-guards')) : typeof define === 'function' && define.amd ? define('@terminus/ngx-tools/jwt', ['exports', '@terminus/ngx-tools/utilities', '@angular/core', '@ngrx/effects', '@ngrx/store', '@terminus/ngx-tools/browser', 'rxjs', 'rxjs/internal/scheduler/async', 'rxjs/operators', '@angular/common/http', '@terminus/ngx-tools/type-guards'], factory) : (global = global || self, factory((global.terminus = global.terminus || {}, global.terminus['ngx-tools'] = global.terminus['ngx-tools'] || {}, global.terminus['ngx-tools'].jwt = {}), global.terminus['ngx-tools'].utilities, global.ng.core, global.ngrx.effects, global.ngrx.store, global.terminus['ngx-tools'].browser, global.rxjs, global.rxjs['internal/scheduler/async'], global.rxjs.operators, global.ng.common.http, global.terminus['ngx-tools']['type-guards'])); }(this, (function (exports, utilities, core, effects, store, browser, rxjs, async, operators, http, typeGuards) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __param(paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __exportStar(m, exports) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; function __await(v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } function __asyncGenerator(thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } } function __asyncDelegator(o) { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } } function __asyncValues(o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; function __importStar(mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result.default = mod; return result; } function __importDefault(mod) { return (mod && mod.__esModule) ? mod : { default: mod }; } function __classPrivateFieldGet(receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); } function __classPrivateFieldSet(receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; } /* eslint-disable @typescript-eslint/no-magic-numbers, no-bitwise, no-mixed-operators */ /** * The code was extracted from: * https://github.com/davidchambers/Base64.js */ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var InvalidCharacterError = /** @class */ (function (_super) { __extends(InvalidCharacterError, _super); function InvalidCharacterError(message) { var _this = _super.call(this, message) || this; _this.message = message; return _this; } return InvalidCharacterError; }(Error)); /** * Encode value * * @param input * @returns The encoded value */ function atobPolyfill(input) { var str = String(input).replace(/=+$/, ''); if (str.length % 4 === 1) { throw new InvalidCharacterError("NGXTools: 'atob' failed: The string to be decoded is not correctly encoded."); } var output = ''; for ( // initialize result and counters var bc = 0, bs = void 0, buffer = void 0, idx = 0; // get next character buffer = str.charAt(idx++); // character found in table? initialize bit storage and add its ascii value; // eslint-disable-next-line @typescript-eslint/no-explicit-any ~buffer && (bs = bc % 4 ? (bs * 64) + buffer : buffer, // and if not first of each 4 characters, // convert the first 8 bits to one ascii character bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) { // try to find character in table (0-63, not found => -1) buffer = chars.indexOf(buffer); } return output; } /* eslint-disable @typescript-eslint/no-magic-numbers */ var localAtob = window.atob || atobPolyfill; /** * Decode unicode value * * @param str * @returns The decoded value */ var b64DecodeUnicode = function (str) { return decodeURIComponent(localAtob(str).replace(/(.)/g, function (m, p) { var code = p.charCodeAt(0).toString(16).toUpperCase(); if (code.length < 2) { code = "0" + code; } return "%" + code; })); }; var ɵ0 = b64DecodeUnicode; // eslint-disable-next-line camelcase /** * Decode url encoded value * * @param str * @returns The decoded value */ // eslint-disable-next-line camelcase function base64_url_decode(str) { var output = str.replace(/-/g, '+').replace(/_/g, '/'); switch (output.length % 4) { case 0: break; case 2: output += '=='; break; case 3: output += '='; break; default: throw new Error('Illegal base64url string!'); } try { return b64DecodeUnicode(output); } catch (err) { return localAtob(output); } } // Rewritten from https://github.com/auth0/jwt-decode/tree/master/lib to be typescript compliant var InvalidTokenError = /** @class */ (function () { function InvalidTokenError(message) { this.message = message; } return InvalidTokenError; }()); // eslint-disable-next-line @typescript-eslint/no-explicit-any InvalidTokenError.prototype.name = 'InvalidTokenError'; /** * Decode JWT token * * @param token * @param options * @returns Token */ function jwtDecode(token, options) { if (typeof token !== 'string') { throw new InvalidTokenError('Invalid token specified'); } options = options || {}; var pos = options.header === true ? 0 : 1; try { return JSON.parse(base64_url_decode(token.split('.')[pos])); } catch (e) { if (e instanceof Error) { throw new InvalidTokenError("Invalid token specified: " + e.message); } else { throw e; } } } (function (ActionTypes) { ActionTypes["StoreToken"] = "[ngx-tools-jwt-token-provider] Store Token"; ActionTypes["TokenNearingExpiration"] = "[ngx-tools-jwt-token-provider] Token Nearing Expiration"; ActionTypes["TokenExpired"] = "[ngx-tools-jwt-token-provider] Token Expired"; ActionTypes["EscalateToken"] = "[ngx-tools-jwt-token-provider] Escalate Token"; ActionTypes["EscalationSuccess"] = "[ngx-tools-jwt-token-provider] Escalation Success"; ActionTypes["EscalationFailed"] = "[ngx-tools-jwt-token-provider] Escalation Failed"; ActionTypes["AllTokensExpired"] = "[ngx-tools-jwt-token-provider] All Tokens have Expired"; ActionTypes["InitialTokenExtracted"] = "[ngx-tools-jwt-token-provider] Initial Token Extracted"; ActionTypes["FailedToActivateRoute"] = "[ngx-tools-jwt-token-provider] Failed To Activate Route"; })(exports.JwtTokenManagementActionTypes || (exports.JwtTokenManagementActionTypes = {})); utilities.defineTypeEnum(exports.JwtTokenManagementActionTypes); /** * InitialTokenExtracted */ var InitialTokenExtracted = /** @class */ (function () { function InitialTokenExtracted(token) { this.token = token; this.type = exports.JwtTokenManagementActionTypes.InitialTokenExtracted; } return InitialTokenExtracted; }()); /** * FailedToActivateRoute */ var FailedToActivateRoute = /** @class */ (function () { function FailedToActivateRoute() { this.type = exports.JwtTokenManagementActionTypes.FailedToActivateRoute; } return FailedToActivateRoute; }()); /** * StoreToken */ var StoreToken = /** @class */ (function () { function StoreToken(_a) { var tokenName = _a.tokenName, token = _a.token, isDefaultToken = _a.isDefaultToken; this.type = exports.JwtTokenManagementActionTypes.StoreToken; this.tokenName = tokenName; this.token = token; this.isDefaultToken = !!isDefaultToken; } return StoreToken; }()); /** * TokenExpired */ var TokenExpired = /** @class */ (function () { function TokenExpired(_a) { var tokenName = _a.tokenName, token = _a.token; this.type = exports.JwtTokenManagementActionTypes.TokenExpired; this.tokenName = tokenName; this.token = token; } return TokenExpired; }()); /** * AllTokensExpired */ var AllTokensExpired = /** @class */ (function () { function AllTokensExpired() { this.type = exports.JwtTokenManagementActionTypes.AllTokensExpired; } return AllTokensExpired; }()); /** * TokenNearingExpiration */ var TokenNearingExpiration = /** @class */ (function () { function TokenNearingExpiration(_a) { var tokenName = _a.tokenName, token = _a.token; this.type = exports.JwtTokenManagementActionTypes.TokenNearingExpiration; this.tokenName = tokenName; this.token = token; } return TokenNearingExpiration; }()); /** * EscalateToken */ var EscalateToken = /** @class */ (function () { function EscalateToken(tokenName) { this.tokenName = tokenName; this.type = exports.JwtTokenManagementActionTypes.EscalateToken; } return EscalateToken; }()); /** * EscalationSuccess */ var EscalationSuccess = /** @class */ (function () { function EscalationSuccess(tokenName) { this.tokenName = tokenName; this.type = exports.JwtTokenManagementActionTypes.EscalationSuccess; } return EscalationSuccess; }()); /** * EscalationFailed */ var EscalationFailed = /** @class */ (function () { function EscalationFailed(tokenName) { this.tokenName = tokenName; this.type = exports.JwtTokenManagementActionTypes.EscalationFailed; } return EscalationFailed; }()); var JWT_TOKEN_MANAGEMENT_STATE_TOKEN = 'ngx-tools-jwtTokenManagement'; var jwtModuleEmptyState = { jwtTokens: { initialTokenStatus: 'empty', tokens: {}, }, }; var getJwtTokenRoot = function () { return store.createFeatureSelector(JWT_TOKEN_MANAGEMENT_STATE_TOKEN); }; /** * Return all current tokens */ var getTokens = function () { return store.createSelector(getJwtTokenRoot(), function (jwtTokenState) { return (jwtTokenState ? jwtTokenState.jwtTokens.tokens : {}); }); }; var getDefaultToken = function () { return store.createSelector(getJwtTokenRoot(), function (jwtTokenState) { return (jwtTokenState ? jwtTokenState.jwtTokens.defaultToken : undefined); }); }; var tokenForWithoutDefault = function (serviceName) { return store.createSelector(getTokens(), function (userState) { return userState[serviceName]; }); }; var tokenFor = function (serviceName) { return store.createSelector(getDefaultToken(), tokenForWithoutDefault(serviceName), function (defaultToken, serviceToken) { return serviceToken || defaultToken; }); }; var claimsFor = function (serviceName) { return store.createSelector(tokenFor(serviceName), function (token) { if (token) { try { return jwtDecode(token); } catch (e) { if (e.name === 'InvalidTokenError') { return null; } throw e; } } else { return null; } }); }; var claimValue = function (serviceName, claimName) { return store.createSelector(claimsFor(serviceName), function (claims) { return (claims ? claims[claimName] : null); }); }; var INITIAL_TOKEN_NAME = new core.InjectionToken('jwt-token-managment INITIAL_JWT_TOKEN_NAME'); // TODO: Scheduler is marked as deprecated to stop others from using although it is not technically deprecated from what I can tell. The // 'correct' path would be to create our own class extending `SchedulerLike`. https://github.com/GetTerminus/ngx-tools/issues/287 // eslint-disable-next-line deprecation/deprecation var SCHEDULER = new core.InjectionToken('scheduler'); var ESCALATION_WAIT_TIME = new core.InjectionToken('wait time'); var FORBIDDEN_ERROR = 403; var DEFAULT_ESCALATION_WAIT_TIME = 30000; var RetryWithEscalation = /** @class */ (function () { function RetryWithEscalation(actions$, // eslint-disable-next-line @typescript-eslint/no-explicit-any store, // TODO: Scheduler is marked as deprecated to stop others from using although it is not technically deprecated // from what I can tell. The 'correct' path would be to create our own class extending `SchedulerLike`. // https://github.com/GetTerminus/ngx-tools/issues/287 // eslint-disable-next-line deprecation/deprecation scheduler, waitTime) { this.actions$ = actions$; this.store = store; this.scheduler = scheduler; this.waitTime = waitTime; } RetryWithEscalation.prototype.retryWithEscalation = function (tokenName) { var _this = this; // eslint-disable-next-line @typescript-eslint/no-explicit-any return function (source) { return source.pipe(operators.retryWhen(function (errors) { var DELAY_MS = 10; var tries = 0; return errors.pipe(operators.mergeMap(function (err) { if (tries > 0 || err instanceof Error || err.status !== FORBIDDEN_ERROR) { return rxjs.throwError(err); } tries += 1; _this.store.dispatch(new EscalateToken(tokenName)); return rxjs.merge(_this.waitForResult(tokenName), _this.expirationTimer()).pipe(operators.take(1), operators.delay(DELAY_MS, _this.scheduler || async.async)); })); })); }; }; RetryWithEscalation.prototype.waitForResult = function (tokenName) { var _this = this; return this.actions$ .pipe(effects.ofType(exports.JwtTokenManagementActionTypes.EscalationFailed, exports.JwtTokenManagementActionTypes.EscalationSuccess), operators.filter(function (a) { return a.tokenName === tokenName; }), operators.switchMap(function (escResult) { if (escResult.type === exports.JwtTokenManagementActionTypes.EscalationSuccess) { return 'complete'; } return _this.failureError(); })); }; RetryWithEscalation.prototype.expirationTimer = function () { var _this = this; return rxjs.timer(this.waitTime || DEFAULT_ESCALATION_WAIT_TIME, this.scheduler || async.async).pipe(operators.switchMap(function () { return _this.failureError(); })); }; RetryWithEscalation.prototype.failureError = function () { return rxjs.throwError(new Error('Failed to escalate token')); }; RetryWithEscalation.ctorParameters = function () { return [ { type: effects.Actions }, { type: store.Store }, { type: rxjs.Scheduler, decorators: [{ type: core.Optional }, { type: core.Inject, args: [SCHEDULER,] }] }, { type: Number, decorators: [{ type: core.Optional }, { type: core.Inject, args: [ESCALATION_WAIT_TIME,] }] } ]; }; RetryWithEscalation = __decorate([ core.Injectable(), __param(2, core.Optional()), __param(2, core.Inject(SCHEDULER)), __param(3, core.Optional()), __param(3, core.Inject(ESCALATION_WAIT_TIME)) ], RetryWithEscalation); return RetryWithEscalation; }()); var SECONDS_BEFORE_EXPIRATION_TO_NOTIFY = new core.InjectionToken('wait time'); var SECONDS_IN_MINUTE = 60; var DEFAULT_MINUTES_BEFORE_EXPIRATION_TO_NOTIFY = 5; var DEFAULT_SECONDS_BEFORE_EXPIRATION_TO_NOTIFY = DEFAULT_MINUTES_BEFORE_EXPIRATION_TO_NOTIFY * SECONDS_IN_MINUTE; var CLEANUP_DELAY = 100; var TOKENS_EXPIRED_DELAY = 10; var MS_IN_SECONDS = 1000; var JwtTokenProviderEffects = /** @class */ (function () { function JwtTokenProviderEffects(actions$, // eslint-disable-next-line @typescript-eslint/no-explicit-any store, cookieService, initialTokenName, scheduler, timeToWaitBeforeExpiration) { var _this = this; this.actions$ = actions$; this.store = store; this.cookieService = cookieService; this.initialTokenName = initialTokenName; this.scheduler = scheduler; this.timeToWaitBeforeExpiration = timeToWaitBeforeExpiration; this.initializationCleanup$ = rxjs.of(true) .pipe(operators.delay(CLEANUP_DELAY, this.scheduler || async.async), operators.withLatestFrom(this.store.select(getTokens())), operators.map(function (_a) { var _b = __read(_a, 2), _ = _b[0], tokens = _b[1]; return tokens; }), operators.take(1), operators.flatMap(function (tokens) { var actions = []; for (var tokenName in tokens) { if (tokens.hasOwnProperty(tokenName)) { var token = tokens[tokenName]; if (token) { actions.push(new StoreToken({ tokenName: tokenName, token: token, })); } } } return actions; })); this.allTokensExpired$ = this.actions$ .pipe(effects.ofType(exports.JwtTokenManagementActionTypes.TokenExpired), operators.delay(TOKENS_EXPIRED_DELAY, this.scheduler || async.async), operators.withLatestFrom(this.store.select(getTokens())), operators.map(function (_a) { var _b = __read(_a, 2), _ = _b[0], tokens = _b[1]; return tokens; }), operators.filter(function (tokens) { return Object.keys(tokens).length === 0; }), operators.map(function (tokens) { return new AllTokensExpired(); })); this.notifyOfTokenExpiration$ = this.actions$ .pipe(effects.ofType(exports.JwtTokenManagementActionTypes.StoreToken), // eslint-disable-next-line max-len operators.map(function (action) { return [action, jwtDecode(action.token)]; }), operators.filter(function (a) { return a[1].exp !== undefined; }), operators.mergeMap(function (_a) { var _b = __read(_a, 2), action = _b[0], claims = _b[1]; var currentEpoch = Math.ceil((new Date()).getTime() / MS_IN_SECONDS); if (claims.exp > currentEpoch) { var expiresIn = claims.exp - currentEpoch; var expirationBuffer = _this.timeToWaitBeforeExpiration || DEFAULT_SECONDS_BEFORE_EXPIRATION_TO_NOTIFY; var expirationNearIn = 0; if (expiresIn < expirationBuffer) { expirationNearIn = 1; } else { expirationNearIn = expiresIn - expirationBuffer; } return rxjs.merge(_this.buildDelayedExpirationObservable(expirationNearIn * MS_IN_SECONDS, action, false), _this.buildDelayedExpirationObservable(expiresIn * MS_IN_SECONDS, action, true)); } return rxjs.of(new TokenExpired({ tokenName: action.tokenName, token: action.token, })); })); this.initialCookieLoader$ = function (_a) { var _b = (_a === void 0 ? {} : _a).currentState, currentState = _b === void 0 ? _this.store.select(getJwtTokenRoot()) : _b; return rxjs.of(true).pipe(operators.take(1), operators.withLatestFrom(currentState), operators.filter(function (_a) { var _b = __read(_a, 2), _ = _b[0], state = _b[1]; return !!(state && state.jwtTokens.initialTokenStatus === 'uninitialized'); }), operators.mergeMap(function (_a) { var _b = __read(_a, 2), a = _b[0], _ = _b[1]; var cookie = _this.cookieService.get('jwt_cookie'); if (cookie.length > 0) { return [ new InitialTokenExtracted(cookie), new StoreToken({ tokenName: _this.initialTokenName, token: cookie, isDefaultToken: true, }), ]; } return [ new InitialTokenExtracted(cookie), ]; })); }; } /* * This next function is being excluded from coverage due the complexities of testing the `delay` function. * In order to test as much as possible, each piece has been separated into smaller testable functions. */ JwtTokenProviderEffects.prototype.buildDelayedExpirationObservable = function (emitTime, action, expired) { var outputActionArgs = { tokenName: action.tokenName, token: action.token, }; return rxjs.timer(emitTime, this.scheduler || async.async).pipe(operators.take(1), operators.map(function () { return (expired ? new TokenExpired(outputActionArgs) : new TokenNearingExpiration(outputActionArgs)); })); }; JwtTokenProviderEffects.ctorParameters = function () { return [ { type: effects.Actions }, { type: store.Store }, { type: browser.TsCookieService }, { type: String, decorators: [{ type: core.Inject, args: [INITIAL_TOKEN_NAME,] }] }, { type: rxjs.Scheduler, decorators: [{ type: core.Optional }, { type: core.Inject, args: [SCHEDULER,] }] }, { type: Number, decorators: [{ type: core.Optional }, { type: core.Inject, args: [SECONDS_BEFORE_EXPIRATION_TO_NOTIFY,] }] } ]; }; __decorate([ effects.Effect() ], JwtTokenProviderEffects.prototype, "initializationCleanup$", void 0); __decorate([ effects.Effect() ], JwtTokenProviderEffects.prototype, "allTokensExpired$", void 0); __decorate([ effects.Effect() ], JwtTokenProviderEffects.prototype, "notifyOfTokenExpiration$", void 0); __decorate([ effects.Effect() ], JwtTokenProviderEffects.prototype, "initialCookieLoader$", void 0); JwtTokenProviderEffects = __decorate([ core.Injectable(), __param(3, core.Inject(INITIAL_TOKEN_NAME)), __param(4, core.Optional()), __param(4, core.Inject(SCHEDULER)) // TODO: Scheduler is marked as deprecated to stop others from using although it is not technically deprecated from // what I can tell. The 'correct' path would be to create our own class extending `SchedulerLike`. // https://github.com/GetTerminus/ngx-tools/issues/287 // eslint-disable-next-line deprecation/deprecation , __param(5, core.Optional()), __param(5, core.Inject(SECONDS_BEFORE_EXPIRATION_TO_NOTIFY)) ], JwtTokenProviderEffects); return JwtTokenProviderEffects; }()); var _a; var jwtEmptyStateReset = (_a = {}, _a[JWT_TOKEN_MANAGEMENT_STATE_TOKEN] = jwtModuleEmptyState, _a); var DefaultTokenRequired = /** @class */ (function () { function DefaultTokenRequired( // eslint-disable-next-line @typescript-eslint/no-explicit-any store$1) { this.store = store$1; this.currentLoadState = this.store.pipe(store.select(getJwtTokenRoot()), operators.map(function (s) { return (s && s.jwtTokens.initialTokenStatus) || 'uninitialized'; })); this.currentToken = this.store.pipe(store.select(getDefaultToken()), operators.map(function (s) { return s || ''; })); } DefaultTokenRequired.prototype.canActivate = function () { var _this = this; return this.currentLoadState.pipe(operators.filter(function (s) { return s !== 'uninitialized'; }), operators.withLatestFrom(this.currentToken), operators.map(function (_a) { var _b = __read(_a, 2), _ = _b[0], token = _b[1]; return token.length > 0; }), operators.tap(function (result) { if (!result) { _this.store.dispatch(new FailedToActivateRoute()); } })); }; DefaultTokenRequired.ctorParameters = function () { return [ { type: store.Store } ]; }; DefaultTokenRequired = __decorate([ core.Injectable() ], DefaultTokenRequired); return DefaultTokenRequired; }()); var initialState = { initialTokenStatus: 'uninitialized', tokens: {}, }; /** * @param state * @param action */ function jwtTokenProviderReducer(state, action) { if (state === void 0) { state = initialState; } switch (action.type) { case exports.JwtTokenManagementActionTypes.InitialTokenExtracted: { if (state.initialTokenStatus !== 'uninitialized') { return state; } if (action.token.length === 0) { return { initialTokenStatus: 'empty', tokens: {}, }; } return { initialTokenStatus: 'loaded', defaultToken: action.token, tokens: {}, }; } case exports.JwtTokenManagementActionTypes.StoreToken: { var newState = __assign(__assign({}, state), { tokens: __assign({}, state.tokens) }); if (action.isDefaultToken) { newState.defaultToken = action.token; newState.tokens = {}; } newState.tokens[action.tokenName] = action.token; return newState; } case exports.JwtTokenManagementActionTypes.TokenExpired: { var newState = __assign(__assign({}, state), { tokens: __assign({}, state.tokens) }); if (state.defaultToken && state.defaultToken === action.token) { delete newState.defaultToken; } for (var k in state.tokens) { if (state.tokens[k] && state.tokens[k] === action.token) { delete newState.tokens[k]; } } return newState; } default: { return state; } } } var TOKEN_NOT_FOUND_ERROR = new Error('Token Not found in response'); var TokenExtractor = /** @class */ (function () { function TokenExtractor( // eslint-disable-next-line @typescript-eslint/no-explicit-any store) { this.store = store; } // eslint-disable-next-line @typescript-eslint/no-explicit-any TokenExtractor.prototype.extractJwtToken = function (_a) { var _this = this; var tokenName = _a.tokenName, isDefaultToken = _a.isDefaultToken; return function (source) { return source.pipe(operators.tap(function (request) { var token = _this.extractTokenFromResponse(request); if (token === '') { throw TOKEN_NOT_FOUND_ERROR; } else { _this.store.dispatch(new StoreToken({ tokenName: tokenName, token: token, isDefaultToken: isDefaultToken, })); } })); }; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any TokenExtractor.prototype.extractTokenFromResponse = function (input) { var token = ''; if (typeGuards.isTokenResponse(input)) { token = input.token; } else if (typeGuards.isHttpResponse(input)) { var authHeader = input.headers.get('Authorization'); var tokenStartsAtChar = 7; if (authHeader && authHeader.startsWith('Bearer ')) { token = authHeader.substr(tokenStartsAtChar); } } return token; }; TokenExtractor.ctorParameters = function () { return [ { type: store.Store } ]; }; TokenExtractor = __decorate([ core.Injectable() ], TokenExtractor); return TokenExtractor; }()); var TokenEscalator = /** @class */ (function () { function TokenEscalator(actions$, // eslint-disable-next-line @typescript-eslint/no-explicit-any store, http, tokenExtractor) { this.actions$ = actions$; this.store = store; this.http = http; this.tokenExtractor = tokenExtractor; } // eslint-disable-next-line @typescript-eslint/no-explicit-any TokenEscalator.prototype.escalateToken = function (_a) { var _this = this; var tokenName = _a.tokenName, authorizeUrl = _a.authorizeUrl, isDefaultToken = _a.isDefaultToken; return this.actions$ .pipe(effects.ofType(exports.JwtTokenManagementActionTypes.EscalateToken), operators.filter(function (a) { return a.tokenName === tokenName; }), operators.withLatestFrom(authorizeUrl, this.store.select(tokenFor(tokenName))), operators.switchMap(function (_a) { var _b = __read(_a, 3), action = _b[0], url = _b[1], currentToken = _b[2]; var headers = new http.HttpHeaders({ Authorization: "Bearer " + currentToken }); return _this.http.get(url, { headers: headers }).pipe(_this.tokenExtractor.extractJwtToken({ tokenName: tokenName, isDefaultToken: isDefaultToken, }), operators.map(function () { return new EscalationSuccess(tokenName); }), operators.catchError(function () { return rxjs.of(new EscalationFailed(tokenName)); })); })); }; TokenEscalator.ctorParameters = function () { return [ { type: effects.Actions }, { type: store.Store }, { type: http.HttpClient }, { type: TokenExtractor } ]; }; TokenEscalator = __decorate([ core.Injectable() ], TokenEscalator); return TokenEscalator; }()); // NOTE: Not sure why this second param is required in strict mode // eslint-disable-next-line @typescript-eslint/no-explicit-any var reducers = { jwtTokens: jwtTokenProviderReducer }; var JwtTokenManagementModule = /** @class */ (function () { function JwtTokenManagementModule() { } JwtTokenManagementModule_1 = JwtTokenManagementModule; JwtTokenManagementModule.forRoot = function (options) { return { ngModule: JwtTokenManagementModule_1, providers: [ { provide: INITIAL_TOKEN_NAME, useValue: options.initialTokenName, }, ], }; }; var JwtTokenManagementModule_1; JwtTokenManagementModule = JwtTokenManagementModule_1 = __decorate([ core.NgModule({ imports: [ http.HttpClientModule, store.StoreModule.forFeature(JWT_TOKEN_MANAGEMENT_STATE_TOKEN, reducers), effects.EffectsModule.forFeature([ JwtTokenProviderEffects, ]), ], providers: [ RetryWithEscalation, TokenEscalator, TokenExtractor, DefaultTokenRequired, ], }) ], JwtTokenManagementModule); return JwtTokenManagementModule; }()); /** * Regenerate on retry * * @param obs * @returns Observable */ var regenerateOnRetry = function (obs) { return rxjs.of(true).pipe(operators.switchMap(function () { return obs(); })); }; exports.ActionTypes = exports.JwtTokenManagementActionTypes; exports.AllJwtTokensExpired = AllTokensExpired; exports.AllTokensExpired = AllTokensExpired; exports.DefaultTokenRequired = DefaultTokenRequired; exports.ESCALATION_WAIT_TIME = ESCALATION_WAIT_TIME; exports.EscalateJwtToken = EscalateToken; exports.EscalateToken = EscalateToken; exports.EscalationFailed = EscalationFailed; exports.EscalationSuccess = EscalationSuccess; exports.FailedToActivateRoute = FailedToActivateRoute; exports.INITIAL_TOKEN_NAME = INITIAL_TOKEN_NAME; exports.InitialTokenExtracted = InitialTokenExtracted; exports.InvalidCharacterError = InvalidCharacterError; exports.InvalidTokenError = InvalidTokenError; exports.JWT_TOKEN_MANAGEMENT_STATE_TOKEN = JWT_TOKEN_MANAGEMENT_STATE_TOKEN; exports.JwtTokenExpired = TokenExpired; exports.JwtTokenManagementModule = JwtTokenManagementModule; exports.JwtTokenNearingExpiration = TokenNearingExpiration; exports.JwtTokenProviderEffects = JwtTokenProviderEffects; exports.RetryWithEscalation = RetryWithEscalation; exports.SCHEDULER = SCHEDULER; exports.SECONDS_BEFORE_EXPIRATION_TO_NOTIFY = SECONDS_BEFORE_EXPIRATION_TO_NOTIFY; exports.StoreJwtToken = StoreToken; exports.StoreToken = StoreToken; exports.TOKEN_NOT_FOUND_ERROR = TOKEN_NOT_FOUND_ERROR; exports.TokenEscalator = TokenEscalator; exports.TokenExpired = TokenExpired; exports.TokenExtractor = TokenExtractor; exports.TokenNearingExpiration = TokenNearingExpiration; exports.atobPolyfill = atobPolyfill; exports.base64_url_decode = base64_url_decode; exports.claimValue = claimValue; exports.claimsFor = claimsFor; exports.getDefaultToken = getDefaultToken; exports.getJwtTokenRoot = getJwtTokenRoot; exports.getTokens = getTokens; exports.initialState = initialState; exports.jwtDecode = jwtDecode; exports.jwtEmptyStateReset = jwtEmptyStateReset; exports.jwtModuleEmptyState = jwtModuleEmptyState; exports.jwtTokenProviderReducer = jwtTokenProviderReducer; exports.reducers = reducers; exports.regenerateOnRetry = regenerateOnRetry; exports.tokenFor = tokenFor; exports.tokenForWithoutDefault = tokenForWithoutDefault; exports0 = ɵ0; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=terminus-ngx-tools-jwt.umd.js.map