import { JoseBuilder , Subtle } from 'verifiablecredentials-crypto-sdk-typescript' ; import TestSetup from './TestSetup' ; import { DidDocument } from '@decentralized-identity/did-common-typescript' ; import ClaimToken , { TokenType } from '../lib/verifiable_credential/ClaimToken' ; import ValidationOptions from '../lib/options/ValidationOptions' ; import { KeyReference , IExpectedBase , IExpectedSelfIssued , IExpectedIdToken , IExpectedSiop , IExpectedVerifiablePresentation , IExpectedVerifiableCredential , JsonWebSignatureToken , TokenPayload , createJwkThumbprint } from '../lib/index' ; import VerifiableCredentialConstants from '../lib/verifiable_credential/VerifiableCredentialConstants' ; export class IssuanceHelpers { public static readonly jti : string = 'testJti' ; /**
     * Create siop request
     */ public static async createSiopRequestWithPayload ( setup , siop , key ) { const claimToken = await IssuanceHelpers . signAToken ( setup , siop , '' , key ) ; return claimToken ; } /**
     * Create siop request
     */ public static async createSiopRequest ( setup , key , contract , nonce , attestations ) { let siop = { nonce , contract , attestations , iss : 'https://self-issued.me' , aud : setup . AUDIENCE , jti : IssuanceHelpers . jti , sub_jwk : key , sub : createJwkThumbprint ( key ) , did : setup . defaultUserDid } ; if ( setup . siopMutator ) { siop = setup . siopMutator ( siop ) ; } return IssuanceHelpers . createSiopRequestWithPayload ( setup , siop , key ) ; } param claims public static createSelfIssuedToken ( claims ) { const header = { alg : "none" , typ : 'JWT' } ; const jwt = JsonWebSignatureToken . encode ( header , claims ) ; return new ClaimToken ( TokenType . selfIssued , jwt , '' ) ; } param claims public static async createVc ( setup , credentialSubject , configuration , jwkPrivate , jwkPublic ) { await this . resolverMock ( setup , setup . defaultIssuerDid , jwkPrivate , jwkPublic ) ; const statusUrl = 'https://portableidentitycards.azure-api.net/42b39d9d-0cdd-4ae0-b251-b7b39a561f91/api/portable/v1.0/status' ; setup . fetchMock . post ( statusUrl , { } , { overwriteRoutes : true } ) ; let vcTemplate = { "jti" : "urn:pic:80a509d2-99d4-4d6c-86a7-7b2636944080" , "vc" : { "@context" : [ "https://www.w3.org/2018/credentials/v1" , "https://portableidentitycards.azure-api.net/42b39d9d-0cdd-4ae0-b251-b7b39a561f91/api/portable/v1.0/contracts/test/schema" ] , "type" : [ "VerifiableCredential" , "DrivingLicense" ] , "credentialSubject" : { } , "credentialStatus" : { "id" : `${ statusUrl }` , "type" : "PortableIdentityCardServiceCredentialStatus2020" } } , iss : `${ setup . defaultIssuerDid }` , sub : `${ setup . defaultUserDid }` } ; vcTemplate . vc . credentialSubject = credentialSubject ; return IssuanceHelpers . signAToken ( setup , vcTemplate , configuration , jwkPrivate ) ; } param claims public static async createVp ( setup , vcs , jwkPrivate ) { let vpTemplate = { "jti" : "baab2cdccb38408d8f1179071fe37dbe" , "scope" : "openid did_authn verify" , "vp" : { "@context" : [ "https://www.w3.org/2018/credentials/v1" ] , "type" : [ "VerifiablePresentation" ] , "verifiableCredential" : [ ] } , iss : `${ setup . defaultUserDid }` , aud : `${ setup . defaultIssuerDid }` , } ; for ( let inx = 0 ; inx < vcs . length ; inx ++ ) { ( vpTemplate . vp . verifiableCredential as string [ ] ) . push ( < string > vcs [ inx ] . rawToken ) ; } return IssuanceHelpers . signAToken ( setup , vpTemplate , '' , jwkPrivate ) ; } /**
     * Generate a signing keys and set the configuration mock
     */ public static async generateSigningKey ( _setup , kid ) { const generator = new Subtle ( ) ; const key = await generator . generateKey ( < any > { name : "RSASSA-PKCS1-v1_5" , modulusLength : 2048 , publicExponent : new Uint8Array ( [ 0x01 , 0x00 , 0x01 ] ) , hash : { name : "SHA-256" } , } , true , [ "sign" , "verify" ] ) ; const jwkPublic = await generator . exportKey ( 'jwk' , key . publicKey ) ; const jwkPrivate = await generator . exportKey ( 'jwk' , key . privateKey ) ; ( < any > jwkPrivate ) . kid = ( < any > jwkPublic ) . kid = kid ; return [ jwkPrivate , jwkPublic ] ; } public static async generateSigningKeyAndSetConfigurationMock ( setup , kid , configuration ? , issuer ? ) { configuration = configuration || setup . defaultIdTokenConfiguration ; issuer = issuer || setup . tokenIssuer ; const jwks = setup . defaultIdTokenJwksConfiguration ; setup . fetchMock . get ( configuration , { "jwks_uri" : `${ jwks }` , "issuer" : `${ issuer }` } , { overwriteRoutes : true } ) ; const [ jwkPrivate , jwkPublic ] = await IssuanceHelpers . generateSigningKey ( setup , kid ) ; setup . fetchMock . get ( jwks , `{"keys": [${ JSON . stringify ( jwkPublic ) }]}` , { overwriteRoutes : true } ) ; return [ jwkPrivate , jwkPublic , configuration ] ; } public static async resolverMock ( setup , did , jwkPrivate ? , jwkPublic ? ) { if ( ! jwkPrivate && ! jwkPublic ) { [ jwkPrivate , jwkPublic ] = await IssuanceHelpers . generateSigningKey ( setup , `${ did }#signing` ) ; } const didDocument = { didDocument : new DidDocument ( { "@context" : "https://w3id.org/did/v1" , id : did , publicKey : < any > [ { id : jwkPublic . kid , type : 'RsaVerificationKey2018' , controller : did , publicKeyJwk : jwkPublic } ] } ) } ; ( didDocument . didDocument as any ) [ '@context' ] = 'https://w3id.org/did/v1' ; const resolverUrl = `${ setup . resolverUrl }/${ did }` ; setup . fetchMock . get ( resolverUrl , didDocument , { overwriteRoutes : true } ) ; return [ didDocument . didDocument , jwkPrivate , jwkPublic ] ; } public static async signAToken ( setup , payload , configuration , jwkPrivate ) { const keyId = new KeyReference ( jwkPrivate . kid ) ; await setup . keyStore . save ( keyId , < any > jwkPrivate ) ; setup . validatorOptions . crypto . builder . useSigningKeyReference ( keyId ) ; setup . validatorOptions . crypto . signingProtocol ( JoseBuilder . JWT ) . builder . useKid ( keyId . keyReference ) ; const signature = await setup . validatorOptions . crypto . signingProtocol ( JoseBuilder . JWT ) . sign ( payload ) ; const token = await setup . validatorOptions . crypto . signingProtocol ( JoseBuilder . JWT ) . serialize ( ) ; let claimToken = ClaimToken . create ( token , configuration ) ; return claimToken ; } public static async createRequest ( setup , tokenDescription , issuance , idTokenIssuer ? , idTokenAudience ? , idTokenExp ? ) { const options = new ValidationOptions ( setup . validatorOptions , tokenDescription ) ; const [ didJwkPrivate , didJwkPublic ] = await IssuanceHelpers . generateSigningKey ( setup , setup . defaulUserDidKid ) ; const [ tokenJwkPrivate , tokenJwkPublic , tokenConfiguration ] = await IssuanceHelpers . generateSigningKeyAndSetConfigurationMock ( setup , setup . defaulIssuerDidKid ) ; const [ didDocument , jwkPrivate2 , jwkPublic2 ] = await IssuanceHelpers . resolverMock ( setup , setup . defaultUserDid , didJwkPrivate , didJwkPublic ) ; const idTokenPayload = { upn : 'jules@pulpfiction.com' , name : 'Jules Winnfield' , iss : idTokenIssuer ?? setup . tokenIssuer , aud : idTokenAudience ?? setup . tokenAudience , exp : idTokenExp ?? Math . trunc ( Date . now ( ) / 1000 ) + 10000 , } ; const idToken = await IssuanceHelpers . signAToken ( setup , idTokenPayload , tokenConfiguration , tokenJwkPrivate ) ; const vcConfiguration = 'https://vcexample.com/schema' ; const vcPayload = { givenName : 'Jules' , familyName : 'Winnfield' } ; const vc = await IssuanceHelpers . createVc ( setup , vcPayload , vcConfiguration , tokenJwkPrivate , tokenJwkPublic ) ; const vp = await IssuanceHelpers . createVp ( setup , [ vc ] , didJwkPrivate ) ; const si = IssuanceHelpers . createSelfIssuedToken ( { name : 'jules' , birthDate : new Date ( ) . toString ( ) } ) ; let attestations ; if ( issuance ) { attestations = { selfIssued : si . rawToken , idTokens : { } , presentations : { } } ; attestations . idTokens [ setup . defaultIdTokenConfiguration ] = idToken . rawToken ; attestations . presentations [ 'DrivingLicense' ] = vp . rawToken ; } else { attestations = { presentations : { } } ; attestations . presentations [ 'DrivingLicense' ] = vp . rawToken ; } const contract = 'https://portableidentitycards.azure-api.net/42b39d9d-0cdd-4ae0-b251-b7b39a561f91/api/portable/v1.0/contracts/test/schema' ; const request = await IssuanceHelpers . createSiopRequest ( setup , didJwkPrivate , issuance ? contract : undefined , '' , attestations ) ; const vcContractIssuers = { } ; vcContractIssuers [ 'DrivingLicense' ] = [ setup . defaultIssuerDid ] ; const idTokenConfiguration = [ setup . defaultIdTokenConfiguration ] ; const expected = [ < IExpectedSelfIssued > { type : TokenType . selfIssued } , < IExpectedIdToken > { type : TokenType . idToken , configuration : idTokenConfiguration , audience : setup . AUDIENCE } , < IExpectedSiop > { type : TokenType . siopIssuance , audience : setup . AUDIENCE } , < IExpectedSiop > { type : TokenType . siopPresentationAttestation , audience : setup . AUDIENCE } , < IExpectedVerifiablePresentation > { type : TokenType . verifiablePresentationJwt , didAudience : setup . defaultIssuerDid } , < IExpectedVerifiableCredential > { type : TokenType . verifiableCredential , contractIssuers : vcContractIssuers } ] ; const siopRequest = { didJwkPrivate , didJwkPublic , tokenJwkPrivate , didDocument , contract , attestations , tokenConfiguration , idToken , vp , vc , si , expected , jti : IssuanceHelpers . jti } ; return [ request , options , siopRequest ] ; } }