UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

99 lines 4.29 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sign = sign; exports.unsign = unsign; exports.isSignatureExpired = isSignatureExpired; const crypto_js_1 = __importDefault(require("crypto-js")); const common_logger_1 = require("../common-logger"); const date_1 = require("./date"); const objects_1 = require("./objects"); const typecheckers_1 = require("./typecheckers"); const logger = new common_logger_1.CommonLogger("crypto"); function toBase64Url(base64) { return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); } function base64UrlEncodeUtf8(value) { const wordArray = crypto_js_1.default.enc.Utf8.parse(value); const base64 = crypto_js_1.default.enc.Base64.stringify(wordArray); return toBase64Url(base64); } function fromBase64Url(base64Url) { const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); const padding = '='.repeat((4 - (base64.length % 4)) % 4); return `${base64}${padding}`; } function base64UrlDecodeUtf8(value) { const base64 = fromBase64Url(value); const wordArray = crypto_js_1.default.enc.Base64.parse(base64); return crypto_js_1.default.enc.Utf8.stringify(wordArray); } /** use the jose library from @kwiz/node for server apps */ function sign(jwtSecret, payload, options) { const header = { alg: "HS256", typ: "JWT" }; const iat = Math.floor(Date.now() / 1000); const exp = (0, typecheckers_1.isNumber)(options === null || options === void 0 ? void 0 : options.exp) ? options === null || options === void 0 ? void 0 : options.exp : (0, typecheckers_1.isDate)(options === null || options === void 0 ? void 0 : options.exp) ? Math.floor(options.exp.getTime() / 1000) : Math.floor((0, date_1.shiftDate)("h1").getTime() / 1000); const base64Header = base64UrlEncodeUtf8(JSON.stringify(header)); const base64Payload = base64UrlEncodeUtf8(JSON.stringify({ ...payload, iat, exp })); const unsignedToken = `${base64Header}.${base64Payload}`; const signatureBase64 = crypto_js_1.default.HmacSHA256(unsignedToken, jwtSecret).toString(crypto_js_1.default.enc.Base64); const signature = toBase64Url(signatureBase64); const token = `${unsignedToken}.${signature}`; return token; } /** use the jose library from @kwiz/node for server apps */ function unsign(jwtSecret, token) { try { if (!token) { throw new Error("Invalid token"); } const parts = token.split('.'); if (parts.length !== 3) { throw new Error("Invalid token"); } const [base64Header, base64Payload, signature] = parts; const unsignedToken = `${base64Header}.${base64Payload}`; const expectedSignatureBase64 = crypto_js_1.default.HmacSHA256(unsignedToken, jwtSecret).toString(crypto_js_1.default.enc.Base64); const expectedSignature = toBase64Url(expectedSignatureBase64); if (expectedSignature !== signature) { throw new Error("Invalid token signature"); } let parsedPayload; try { const payloadJson = base64UrlDecodeUtf8(base64Payload); parsedPayload = JSON.parse(payloadJson); } catch { throw new Error("Invalid token payload"); } const nowSeconds = Math.floor(Date.now() / 1000); const expValue = parsedPayload === null || parsedPayload === void 0 ? void 0 : parsedPayload.exp; const expSeconds = (0, typecheckers_1.isNumber)(expValue) ? expValue : (0, typecheckers_1.isDate)(expValue) ? Math.floor(expValue.getTime() / 1000) : Number(expValue); if (!Number.isNaN(expSeconds) && nowSeconds >= expSeconds) { throw new Error("Token expired"); } return parsedPayload; } catch (e) { logger.error((0, objects_1.GetError)(e)); return null; } } function isSignatureExpired(unsigned) { const now = Math.floor(Date.now() / 1000); return unsigned.iat >= now && now > unsigned.exp; } //# sourceMappingURL=crypto.js.map