@guardian/pan-domain-node
Version:
NodeJs implementation of Guardian pan-domain auth verification
108 lines (107 loc) • 4.55 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PanDomainAuthentication = exports.verifyUser = exports.createCookie = void 0;
const cookie = __importStar(require("cookie"));
const utils_1 = require("./utils");
const api_1 = require("./api");
const fetch_public_key_1 = require("./fetch-public-key");
function createCookie(user, privateKey) {
let queryParams = [];
queryParams.push("firstName=" + user.firstName);
queryParams.push("lastName=" + user.lastName);
queryParams.push("email=" + user.email);
user.avatarUrl && queryParams.push("avatarUrl=" + user.avatarUrl);
queryParams.push("system=" + user.authenticatingSystem);
queryParams.push("authedIn=" + user.authenticatedIn.join(","));
queryParams.push("expires=" + user.expires.toString());
queryParams.push("multifactor=" + String(user.multifactor));
const combined = queryParams.join("&");
const queryParamsString = Buffer.from(combined).toString('base64');
const signature = utils_1.sign(combined, privateKey);
return queryParamsString + "." + signature;
}
exports.createCookie = createCookie;
function verifyUser(pandaCookie, publicKey, currentTime, validateUser) {
if (!pandaCookie) {
return { status: api_1.AuthenticationStatus.INVALID_COOKIE };
}
const { data, signature } = utils_1.parseCookie(pandaCookie);
if (!utils_1.verifySignature(data, signature, publicKey)) {
return { status: api_1.AuthenticationStatus.INVALID_COOKIE };
}
const currentTimestampInMilliseconds = currentTime.getTime();
try {
const user = utils_1.parseUser(data);
const isExpired = user.expires < currentTimestampInMilliseconds;
if (isExpired) {
return { status: api_1.AuthenticationStatus.EXPIRED, user };
}
if (!validateUser(user)) {
return { status: api_1.AuthenticationStatus.NOT_AUTHORISED, user };
}
return { status: api_1.AuthenticationStatus.AUTHORISED, user };
}
catch (error) {
console.error(error);
return { status: api_1.AuthenticationStatus.INVALID_COOKIE };
}
}
exports.verifyUser = verifyUser;
class PanDomainAuthentication {
constructor(cookieName, region, bucket, keyFile, validateUser) {
this.keyCacheTime = 60 * 1000; // 1 minute
this.cookieName = cookieName;
this.region = region;
this.bucket = bucket;
this.keyFile = keyFile;
this.validateUser = validateUser;
this.publicKey = fetch_public_key_1.fetchPublicKey(region, bucket, keyFile);
this.keyUpdateTimer = setInterval(() => this.getPublicKey(), this.keyCacheTime);
}
stop() {
if (this.keyUpdateTimer) {
clearInterval(this.keyUpdateTimer);
this.keyUpdateTimer = undefined;
}
}
getPublicKey() {
return this.publicKey.then(({ key, lastUpdated }) => {
const now = new Date();
const diff = now.getTime() - lastUpdated.getTime();
if (diff > this.keyCacheTime) {
this.publicKey = fetch_public_key_1.fetchPublicKey(this.region, this.bucket, this.keyFile);
return this.publicKey.then(({ key }) => key);
}
else {
return key;
}
});
}
verify(requestCookies) {
return this.getPublicKey().then(publicKey => {
const cookies = cookie.parse(requestCookies);
const pandaCookie = cookies[this.cookieName];
return verifyUser(pandaCookie, publicKey, new Date(), this.validateUser);
});
}
}
exports.PanDomainAuthentication = PanDomainAuthentication;