import { decodeToken , SECP256K1Client , TokenSigner , TokenVerifier } from 'jsontokens' ; import { TokenInterface } from 'jsontokens/lib/decode' ; import { nextYear , makeUUID4 } from '@stacks/common' ; import { getAddressFromPublicKey } from '@stacks/transactions' ; param { Object } profile param { String } privateKey param { Object } subject param { Object } issuer param { String } signingAlgorithm param { Date } issuedAt param { Date } expiresAt returns { Object } 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 ) ; } param { String } token returns { Object } export function wrapProfileToken ( token ) { return { token , decodedToken : decodeToken ( token ) , } ; } param { String } token param { String } publicKeyOrAddress returns { Object } throws 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 as Record < string , string > ) . 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 as string , issuerPublicKey ) ; if ( ! tokenVerifier ) { throw new Error ( 'Invalid token verifier' ) ; } const tokenVerified = tokenVerifier . verify ( token ) ; if ( ! tokenVerified ) { throw new Error ( 'Token verification failed' ) ; } return decodedToken ; } param { String } token param { String } publicKeyOrAddress returns { Object } throws 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 as Record < string , any > ; } } return profile ; }