@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
99 lines • 4.29 kB
JavaScript
;
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