@stacks/auth
Version:
Authentication for Stacks apps.
142 lines • 5.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyAuthResponse = exports.verifyAuthRequestAndLoadManifest = exports.verifyAuthRequest = exports.isRedirectUriValid = exports.isManifestUriValid = exports.isExpirationDateValid = exports.isIssuanceDateValid = exports.doPublicKeysMatchIssuer = exports.doSignaturesMatchPublicKeys = void 0;
const common_1 = require("@stacks/common");
const encryption_1 = require("@stacks/encryption");
const jsontokens_1 = require("jsontokens");
const dids_1 = require("./dids");
const provider_1 = require("./provider");
function doSignaturesMatchPublicKeys(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
const publicKeys = payload.public_keys;
if (publicKeys.length === 1) {
const publicKey = publicKeys[0];
try {
const tokenVerifier = new jsontokens_1.TokenVerifier('ES256k', publicKey);
return tokenVerifier.verify(token);
}
catch (e) {
return false;
}
}
else {
throw new Error('Multiple public keys are not supported');
}
}
exports.doSignaturesMatchPublicKeys = doSignaturesMatchPublicKeys;
function doPublicKeysMatchIssuer(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
const publicKeys = payload.public_keys;
const addressFromIssuer = (0, dids_1.getAddressFromDID)(payload.iss);
if (publicKeys.length === 1) {
const addressFromPublicKeys = (0, encryption_1.publicKeyToBtcAddress)(publicKeys[0]);
if (addressFromPublicKeys === addressFromIssuer) {
return true;
}
}
else {
throw new Error('Multiple public keys are not supported');
}
return false;
}
exports.doPublicKeysMatchIssuer = doPublicKeysMatchIssuer;
function isIssuanceDateValid(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
if (payload.iat) {
if (typeof payload.iat !== 'number') {
return false;
}
const issuedAt = new Date(payload.iat * 1000);
if (new Date().getTime() < issuedAt.getTime()) {
return false;
}
else {
return true;
}
}
else {
return true;
}
}
exports.isIssuanceDateValid = isIssuanceDateValid;
function isExpirationDateValid(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
if (payload.exp) {
if (typeof payload.exp !== 'number') {
return false;
}
const expiresAt = new Date(payload.exp * 1000);
if (new Date().getTime() > expiresAt.getTime()) {
return false;
}
else {
return true;
}
}
else {
return true;
}
}
exports.isExpirationDateValid = isExpirationDateValid;
function isManifestUriValid(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
return (0, common_1.isSameOriginAbsoluteUrl)(payload.domain_name, payload.manifest_uri);
}
exports.isManifestUriValid = isManifestUriValid;
function isRedirectUriValid(token) {
const payload = (0, jsontokens_1.decodeToken)(token).payload;
if (typeof payload === 'string') {
throw new Error('Unexpected token payload type of string');
}
return (0, common_1.isSameOriginAbsoluteUrl)(payload.domain_name, payload.redirect_uri);
}
exports.isRedirectUriValid = isRedirectUriValid;
async function verifyAuthRequest(token) {
if ((0, jsontokens_1.decodeToken)(token).header.alg === 'none') {
throw new Error('Token must be signed in order to be verified');
}
const values = await Promise.all([
isExpirationDateValid(token),
isIssuanceDateValid(token),
doSignaturesMatchPublicKeys(token),
doPublicKeysMatchIssuer(token),
isManifestUriValid(token),
isRedirectUriValid(token),
]);
return values.every(val => val);
}
exports.verifyAuthRequest = verifyAuthRequest;
async function verifyAuthRequestAndLoadManifest(token) {
const valid = await verifyAuthRequest(token);
if (!valid) {
throw new Error('Token is an invalid auth request');
}
return (0, provider_1.fetchAppManifest)(token);
}
exports.verifyAuthRequestAndLoadManifest = verifyAuthRequestAndLoadManifest;
async function verifyAuthResponse(token) {
const conditions = await Promise.all([
isExpirationDateValid(token),
isIssuanceDateValid(token),
doSignaturesMatchPublicKeys(token),
doPublicKeysMatchIssuer(token),
]);
return conditions.every(val => val);
}
exports.verifyAuthResponse = verifyAuthResponse;
//# sourceMappingURL=verification.js.map