UNPKG

@fullerstack/ngx-jwt

Version:
186 lines (179 loc) 6.69 kB
import { CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { NgModule, Injectable } from '@angular/core'; import * as i1 from '@fullerstack/ngx-config'; import { DefaultApplicationConfig } from '@fullerstack/ngx-config'; import * as i2 from '@fullerstack/ngx-logger'; import { Base64 } from 'js-base64'; import { mergeWith, cloneDeep } from 'lodash-es'; /** * @license * Copyright Neekware Inc. All Rights Reserved. * * Use of this source code is governed by a proprietary notice * that can be found at http://neekware.com/license/PRI.html */ class JwtModule { } JwtModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); JwtModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, imports: [CommonModule] }); JwtModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, imports: [[CommonModule]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], }] }] }); /** * @license * Copyright Neekware Inc. All Rights Reserved. * * Use of this source code is governed by a proprietary notice * that can be found at http://neekware.com/license/PRI.html */ /** * Default configuration - JWT module */ const DefaultJwtConfig = { // default of 1 second. frontend specific networkDelay: 1, // some backend may still honor requests by `x` seconds after expiry expiryLeeway: 5, }; /** * @license * Copyright Neekware Inc. All Rights Reserved. * * Use of this source code is governed by a proprietary notice * that can be found at http://neekware.com/license/PRI.html */ /** * An injectable class that handles JWT service */ class JwtService { /** * Class constructor * @param options an optional configuration object */ constructor(config, logger) { this.config = config; this.logger = logger; this.nameSpace = 'JWT'; this.options = DefaultApplicationConfig; this.options = mergeWith(cloneDeep({ jwt: DefaultJwtConfig }), this.config.options, (dest, src) => (Array.isArray(dest) ? src : undefined)); this.logger.info(`[${this.nameSpace}] JwtService ready ...`); } /** * Gets the payload portion of a JWT token * @param token JWT token (base64 encrypted) * @returns a payload object or null if decode fails */ getPayload(token) { let parts = []; try { parts = token.split('.'); if (parts.length !== 3) { throw Error('JWT must have 3 parts'); } } catch (e) { this.logger.error(e.message); return undefined; } try { const decoded = Base64.decode(parts[1]); const payload = JSON.parse(decoded); return payload; } catch (e) { this.logger.error('Cannot decode the token'); } return undefined; } /** * Tells if a JWT is token is expired * @param payload JWT payload object * @return true if JWT is already expired, else false */ isExpired(payload) { if (typeof payload === 'string') { payload = this.getPayload(payload); } if (payload) { const offset = (parseInt(payload.lee, 10) || this.options.jwt.expiryLeeway) * 1000; const now = this.utcSeconds(); const expiry = this.utcSeconds(payload.exp); const expired = now > expiry + offset; return expired; } return true; } /** * Calculates the next refresh time * @param payload JWT payload object * @param offset if true, a random time is added to the refresh time * where networkDelay < random < leeway * @returns total number of seconds till expiry or 0 if token is expired */ getRefreshTime(payload, offset = true) { if (typeof payload === 'string') { payload = this.getPayload(payload); } if (payload && !this.isExpired(payload)) { const now = this.utcSeconds(); const expiry = this.utcSeconds(payload.exp); const refresh = Math.floor((expiry - now) / 1000); const random = this.getRandomOffset(payload); const time = offset ? refresh + random : refresh; return time; } return 0; } /** * Calculates a random number where networkDelay < random < leeway * @param payload JWT payload object * @returns a random total number of seconds */ getRandomOffset(payload) { if (typeof payload === 'string') { payload = this.getPayload(payload); } const leeway = payload?.leeway || payload?.lee || this.options?.jwt?.expiryLeeway; const range = { lower: 1, upper: leeway - this.options?.jwt?.networkDelay || 2, }; return Math.floor(Math.random() * range.upper + range.lower); } /** * Calculates the UTC value of date/time in seconds * @param input date/time in seconds * @returns UTC value of date/time in seconds */ utcSeconds(input) { return input ? new Date(0).setUTCSeconds(input).valueOf() : new Date().valueOf(); } } JwtService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, deps: [{ token: i1.ConfigService }, { token: i2.LoggerService }], target: i0.ɵɵFactoryTarget.Injectable }); JwtService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: JwtService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i1.ConfigService }, { type: i2.LoggerService }]; } }); /** * @license * Copyright Neekware Inc. All Rights Reserved. * * Use of this source code is governed by a proprietary notice * that can be found at http://neekware.com/license/PRI.html */ /** * JWT config declaration */ class JwtConfig { } /** * Generated bundle index. Do not edit. */ export { DefaultJwtConfig, JwtConfig, JwtModule, JwtService }; //# sourceMappingURL=fullerstack-ngx-jwt.mjs.map