import { PrivateKey , PublicKeyStatus , Signature , SignatureScheme } from '../crypto' ; import { extractOntId , retrievePublicKey , retrievePublicKeyState } from './functions/public-key.functions' ; import { JwtHeader } from './jwt-header.class' ; import { JwtPayload } from './jwt-payload.class' ; import { VcPayload } from './vc-payload.class' ; import { VpPayload } from './vp-payload.class' ; import { now , str2hexstr } from '../utils' ; /**
 * Representation of JWT Message.
 */ export class JwtMessage { param jwt static deserializeVc ( jwt ) { return JwtMessage . deserialize ( jwt , VcPayload . payloadFromJson ) ; } param jwt static deserializeVp ( jwt ) { return JwtMessage . deserialize ( jwt , VpPayload . payloadFromJson ) ; } private static deserialize ( jwt , deserializeFunction ) { const parts = jwt . split ( '.' , 4 ) ; if ( parts . length < 2 ) { throw new Error ( 'Invalid message.' ) ; } const header = JwtHeader . deserialize ( parts [ 0 ] ) ; const payload = JwtPayload . deserialize ( parts [ 1 ] , deserializeFunction ) ; let signature ; if ( parts . length > 2 ) { if ( header . alg !== undefined && header . kid !== undefined ) { signature = Signature . deserializeJWT ( parts [ 2 ] , SignatureScheme . fromLabelJWS ( header . alg ) , header . kid ) ; } else { throw new Error ( 'Signature scheme was not specified.' ) ; } } return new JwtMessage ( header , payload , signature ) ; } jwtHeader : JwtHeader ; jwtPayload : JwtPayload ; signature ? : Signature ; constructor ( jwtHeader , jwtPayload , signature ) { this . jwtHeader = jwtHeader ; this . jwtPayload = jwtPayload ; this . signature = signature ; } param url param publicKeyId param privateKey param algorithm public async sign ( url , publicKeyId , privateKey , algorithm ? ) { await retrievePublicKey ( publicKeyId , url ) ; if ( algorithm === undefined ) { algorithm = privateKey . algorithm . defaultSchema ; } const message = this . serializeHeaderAndPayload ( algorithm , publicKeyId ) ; this . signature = await privateKey . signAsync ( str2hexstr ( message ) , algorithm , publicKeyId ) ; } param url returns public async verify ( url ) { const signature = this . signature ; if ( signature !== undefined && signature . publicKeyId !== undefined ) { try { const nowTimestamp = Date . now ( ) ; if ( this . jwtPayload . iat !== undefined && this . jwtPayload . iat > nowTimestamp ) { return false ; } if ( this . jwtPayload . exp !== undefined && this . jwtPayload . exp < nowTimestamp ) { return false ; } if ( ! this . verifyIssuerKey ( ) ) { return false ; } if ( ! this . verifyExpiration ( ) ) { return false ; } const state = await retrievePublicKeyState ( signature . publicKeyId , url ) ; if ( state === PublicKeyStatus . REVOKED ) { return false ; } const publicKey = await retrievePublicKey ( signature . publicKeyId , url ) ; const msg = this . serializeHeaderAndPayload ( signature . algorithm , signature . publicKeyId ) ; const msgHex = str2hexstr ( msg ) ; return publicKey . verify ( msgHex , signature ) ; } catch ( e ) { return false ; } } return false ; } /**
     * Serializes the message into JWT format - Base64 encoded string.
     */ public serialize ( ) { const signature = this . signature ; if ( signature !== undefined ) { const signatureEncoded = signature . serializeJWT ( ) ; return this . serializeHeaderAndPayload ( signature . algorithm , signature . publicKeyId ) + '.' + signatureEncoded ; } else { throw new Error ( 'Cannot serialize message without present signature' ) ; } } private serializeHeaderAndPayload ( algorithm ? , publicKeyId ? ) { const headerEncoded = this . jwtHeader . serialize ( algorithm , publicKeyId ) ; const payloadEncoded = this . jwtPayload . serialize ( ) ; return headerEncoded + '.' + payloadEncoded ; } private verifyIssuerKey ( ) { const signature = this . signature ; if ( signature !== undefined && signature . publicKeyId !== undefined ) { const ontId = extractOntId ( signature . publicKeyId ) ; return ontId === this . jwtPayload . iss ; } else { return false ; } } private verifyExpiration ( ) { if ( this . jwtPayload . exp !== undefined ) { return now ( ) < this . jwtPayload . exp ; } else { return true ; } } }