UNPKG

@stacks/auth

Version:

Authentication for Stacks apps.

142 lines 5.27 kB
"use strict"; 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