UNPKG

@stacks/profile

Version:

Library for Stacks profiles

96 lines 3.33 kB
import { decodeToken, SECP256K1Client, TokenSigner, TokenVerifier } from 'jsontokens'; import { nextYear, makeUUID4 } from '@stacks/common'; import { getAddressFromPublicKey } from '@stacks/transactions'; export function signProfileToken(profile, privateKey, subject, issuer, signingAlgorithm = 'ES256K', issuedAt = new Date(), expiresAt = nextYear()) { if (signingAlgorithm !== 'ES256K') { throw new Error('Signing algorithm not supported'); } const publicKey = SECP256K1Client.derivePublicKey(privateKey); if (!subject) { subject = { publicKey }; } if (!issuer) { issuer = { publicKey }; } const tokenSigner = new TokenSigner(signingAlgorithm, privateKey); const payload = { jti: makeUUID4(), iat: issuedAt.toISOString(), exp: expiresAt.toISOString(), subject, issuer, claim: profile, }; return tokenSigner.sign(payload); } export function wrapProfileToken(token) { return { token, decodedToken: decodeToken(token), }; } export function verifyProfileToken(token, publicKeyOrAddress) { const decodedToken = decodeToken(token); const payload = decodedToken.payload; if (typeof payload === 'string') { throw new Error('Unexpected token payload type of string'); } if (payload.hasOwnProperty('subject') && payload.subject) { if (!payload.subject.hasOwnProperty('publicKey')) { throw new Error("Token doesn't have a subject public key"); } } else { throw new Error("Token doesn't have a subject"); } if (payload.hasOwnProperty('issuer') && payload.issuer) { if (!payload.issuer.hasOwnProperty('publicKey')) { throw new Error("Token doesn't have an issuer public key"); } } else { throw new Error("Token doesn't have an issuer"); } if (!payload.hasOwnProperty('claim')) { throw new Error("Token doesn't have a claim"); } const issuerPublicKey = payload.issuer.publicKey; const address = getAddressFromPublicKey(issuerPublicKey); if (publicKeyOrAddress === issuerPublicKey) { } else if (publicKeyOrAddress === address) { } else { throw new Error('Token issuer public key does not match the verifying value'); } const tokenVerifier = new TokenVerifier(decodedToken.header.alg, issuerPublicKey); if (!tokenVerifier) { throw new Error('Invalid token verifier'); } const tokenVerified = tokenVerifier.verify(token); if (!tokenVerified) { throw new Error('Token verification failed'); } return decodedToken; } export function extractProfile(token, publicKeyOrAddress = null) { let decodedToken; if (publicKeyOrAddress) { decodedToken = verifyProfileToken(token, publicKeyOrAddress); } else { decodedToken = decodeToken(token); } let profile = {}; if (decodedToken.hasOwnProperty('payload')) { const payload = decodedToken.payload; if (typeof payload === 'string') { throw new Error('Unexpected token payload type of string'); } if (payload.hasOwnProperty('claim')) { profile = payload.claim; } } return profile; } //# sourceMappingURL=profileTokens.js.map