UNPKG

@hmcts/rpx-xui-node-lib

Version:

Common nodejs library components for XUI

126 lines 5.67 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (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()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.s2s = exports.S2SAuth = void 0; const events_1 = require("events"); const express_1 = require("express"); const jwt_decode_1 = __importDefault(require("jwt-decode")); const otplib_1 = require("otplib"); const common_1 = require("../../common"); const s2s_constants_1 = require("./s2s.constants"); class S2SAuth extends events_1.EventEmitter { constructor(logger = (0, common_1.getLogger)('auth:s2s')) { super(); this.router = (0, express_1.Router)({ mergeParams: true }); this.s2sConfig = { microservice: '', s2sEndpointUrl: '', s2sSecret: '', }; // Cache of S2S tokens, indexed by microservice name this.store = {}; /** * This must be called with a suitable configuration before attempting to use the middleware, or else it will not * have valid parameter values to generate the S2S token. * * @param s2sConfig The S2SConfig containing microservice name, S2S endpoint URL, and S2S secret * @param store The cache for storing S2S tokens, indexed by microservice name */ this.configure = (s2sConfig, store) => { this.s2sConfig = s2sConfig; if (store) { this.store = store; } this.router.use(this.s2sHandler); return this.router; }; this.s2sHandler = (req, res, next) => __awaiter(this, void 0, void 0, function* () { try { const token = yield this.serviceTokenGenerator(); if (token) { req.headers.ServiceAuthorization = `Bearer ${token}`; // If there are no listeners for a success event from this emitter, just return this middleware using // next(), else emit a success event with the S2S token if (!this.listenerCount(s2s_constants_1.S2S.EVENT.AUTHENTICATE_SUCCESS)) { return next(); } else { this.emit(s2s_constants_1.S2S.EVENT.AUTHENTICATE_SUCCESS, token, req, res, next); return; } } } catch (error) { next(error); } }); this.validateCache = () => { const currentTime = Math.floor(Date.now() / 1000); if (!this.store[this.s2sConfig.microservice]) { return false; } return currentTime < this.store[this.s2sConfig.microservice].expiresAt; }; this.getToken = () => { return this.store[this.s2sConfig.microservice]; }; this.deleteCachedToken = () => { if (this.store[this.s2sConfig.microservice]) { delete this.store[this.s2sConfig.microservice]; } }; this.generateToken = () => __awaiter(this, void 0, void 0, function* () { this.logger.info('Generating new S2S token'); const token = yield this.postS2SLease(); const tokenData = (0, jwt_decode_1.default)(token); this.store[this.s2sConfig.microservice] = { expiresAt: tokenData.exp, token, }; return token; }); this.postS2SLease = () => __awaiter(this, void 0, void 0, function* () { const { s2sSecret, microservice, s2sEndpointUrl } = this.s2sConfig; const secretBytes = new otplib_1.ScureBase32Plugin().decode(s2sSecret); const guardrails = (0, otplib_1.createGuardrails)({ MIN_SECRET_BYTES: secretBytes.length }); const oneTimePassword = yield (0, otplib_1.generate)({ secret: s2sSecret, guardrails, strategy: 'totp' }); this.logger.info('Requesting S2S token for microservice:', microservice); const request = yield common_1.http.post(`${s2sEndpointUrl}`, { microservice, oneTimePassword, }); return request.data; }); this.serviceTokenGenerator = () => __awaiter(this, void 0, void 0, function* () { if (this.validateCache()) { const tokenData = this.getToken(); return tokenData.token; } else { return yield this.generateToken(); } }); /** * Get all the events that this strategy emits * @return string[] */ this.getEvents = () => { return Object.values(s2s_constants_1.S2S.EVENT); }; this.logger = logger; } } exports.S2SAuth = S2SAuth; exports.s2s = new S2SAuth(); //# sourceMappingURL=s2s.class.js.map