From 0ed86d8d2b655a718d7c8cf1a946e0150bf877ce Mon Sep 17 00:00:00 2001 From: nklomp Date: Sat, 18 Feb 2023 03:40:30 +0100 Subject: [PATCH] feat: Create VP in OP Authenticator and allow for callbacks --- .../package.json | 1 + .../src/agent/DidAuthSiopOpAuthenticator.ts | 2 +- .../src/session/OpSession.ts | 84 +++++++++++++++---- .../src/types/IDidAuthSiopOpAuthenticator.ts | 6 +- .../ssi-types/src/mapper/credential-mapper.ts | 1 - 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/packages/did-auth-siop-op-authenticator/package.json b/packages/did-auth-siop-op-authenticator/package.json index 976c5edf8..cfae51bae 100644 --- a/packages/did-auth-siop-op-authenticator/package.json +++ b/packages/did-auth-siop-op-authenticator/package.json @@ -17,6 +17,7 @@ "@sphereon/pex": "2.0.0-unstable.5", "@sphereon/ssi-sdk-core": "^0.8.0", "@sphereon/ssi-types": "^0.8.0", + "@veramo/credential-w3c": "4.2.0", "@veramo/core": "4.2.0", "cross-fetch": "^3.1.5", "uuid": "^8.3.2" diff --git a/packages/did-auth-siop-op-authenticator/src/agent/DidAuthSiopOpAuthenticator.ts b/packages/did-auth-siop-op-authenticator/src/agent/DidAuthSiopOpAuthenticator.ts index 6d0afdf12..9a9cd71b0 100644 --- a/packages/did-auth-siop-op-authenticator/src/agent/DidAuthSiopOpAuthenticator.ts +++ b/packages/did-auth-siop-op-authenticator/src/agent/DidAuthSiopOpAuthenticator.ts @@ -75,7 +75,7 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin { supportedDidMethods: args.supportedDidMethods, context, }) - await session.init() + await session.init(args.presentationSignCallback) this.sessions[sessionId] = session return session diff --git a/packages/did-auth-siop-op-authenticator/src/session/OpSession.ts b/packages/did-auth-siop-op-authenticator/src/session/OpSession.ts index 64d6c40c3..70ac5a277 100644 --- a/packages/did-auth-siop-op-authenticator/src/session/OpSession.ts +++ b/packages/did-auth-siop-op-authenticator/src/session/OpSession.ts @@ -1,4 +1,4 @@ -import { DIDDocumentSection, IIdentifier, IKey, TKeyType } from '@veramo/core' +import { DIDDocumentSection, IIdentifier, IKey, PresentationPayload, TKeyType } from '@veramo/core' import { _ExtendedIKey, mapIdentifierKeysToDoc } from '@veramo/utils' import { OP, @@ -19,8 +19,8 @@ import { SupportedVersion, ResolveOpts, } from '@sphereon/did-auth-siop' -import { SubmissionRequirementMatch } from '@sphereon/pex' -import { IVerifiableCredential, IVerifiablePresentation, parseDid } from '@sphereon/ssi-types' +import { PresentationSignCallBackParams, SubmissionRequirementMatch } from '@sphereon/pex' +import { IVerifiableCredential, IVerifiablePresentation, parseDid, W3CVerifiablePresentation } from '@sphereon/ssi-types' import { SuppliedSigner } from '@sphereon/ssi-sdk-core' import { IAuthRequestDetails, @@ -34,8 +34,9 @@ import { IRequiredContext, PerDidResolver, } from '../types/IDidAuthSiopOpAuthenticator' -import { Resolvable } from 'did-resolver' +import { DIDResolutionOptions, DIDResolutionResult, Resolvable } from 'did-resolver' import { KeyAlgo } from '@sphereon/ssi-sdk-core' +import { IVerifyCredentialResult, VerifyCallback, IVerifyCallbackArgs } from '@sphereon/wellknown-dids-client' const fetch = require('cross-fetch') @@ -61,14 +62,17 @@ export class OpSession { this.context = options.context } - public async init() { + public async init(presentationSignCallback: PresentationSignCallback) { this.op = await this.createOp( - this.identifier, - this.verificationMethodSection, - parseDid(this.identifier.did).method, - this.providedDidResolvers, - this.supportedDidMethods || [], - this.expiresIn || 6000, + { + identifier: this.identifier, + verificationMethodSection: this.verificationMethodSection, + didMethod: parseDid(this.identifier.did).method, + providedDidResolvers: this.providedDidResolvers, + supportedDidMethods: this.supportedDidMethods || [], + expiresIn: this.expiresIn || 6000, + presentationSignCallback, + }, this.context ) } @@ -260,18 +264,36 @@ export class OpSession { return SigningAlgo.EDDSA case 'Secp256k1': return SigningAlgo.ES256K + case 'Secp256r1': + return SigningAlgo.ES256 + // @ts-ignore + case 'RSA': + return SigningAlgo.RS256 default: throw Error('Key type not yet supported') } } private async createOp( - identifier: IIdentifier, - verificationMethodSection: DIDDocumentSection | undefined, - didMethod: string, - providedDidResolvers: PerDidResolver[], - supportedDidMethods: string[], - expiresIn: number, + { + identifier, + verificationMethodSection, + didMethod, + providedDidResolvers, + supportedDidMethods, + expiresIn, + presentationSignCallback, + wellknownDidVerifyCallback, + }: { + identifier: IIdentifier + verificationMethodSection: DIDDocumentSection | undefined + didMethod: string + providedDidResolvers?: PerDidResolver[] + supportedDidMethods: string[] + expiresIn: number + presentationSignCallback?: PresentationSignCallback + wellknownDidVerifyCallback?: VerifyCallback + }, context: IRequiredContext ): Promise { if (!identifier.controllerKeyId) { @@ -279,6 +301,24 @@ export class OpSession { } const keyRef = await this.getKey(identifier, verificationMethodSection, context) + const verifyCallback = wellknownDidVerifyCallback + ? wellknownDidVerifyCallback + : async (): Promise => { + return { verified: true } + } + + const presentationCallback = presentationSignCallback + ? presentationSignCallback + : async (args: PresentationSignCallBackParams): Promise => { + const presentation: PresentationPayload = args.presentation as PresentationPayload + const format = args.presentationDefinition.format + return (await context.agent.createVerifiablePresentation({ + presentation, + keyRef: keyRef.kid, + fetchRemoteContexts: true, + proofFormat: format && (format.ldp || format.ldp_vp) ? 'lds' : 'jwt', + })) as W3CVerifiablePresentation + } const builder = OP.builder() .withExpiresIn(expiresIn) @@ -296,11 +336,21 @@ export class OpSession { }, }) .response(ResponseMode.POST) + .addVerifyCallback((args: IVerifyCallbackArgs) => verifyCallback(args)) + .withPresentationSignCallback(presentationCallback) if (supportedDidMethods && supportedDidMethods.length > 0) { supportedDidMethods.forEach((method) => builder.addDidMethod(method)) } if (providedDidResolvers && providedDidResolvers.length > 0) { providedDidResolvers.forEach((providedResolver) => builder.addResolver(providedResolver.didMethod, providedResolver.resolver)) + } else { + class Resolver implements Resolvable { + async resolve(didUrl: string, options?: DIDResolutionOptions): Promise { + return await context.agent.resolveDid({ didUrl, options }) + } + } + + builder.customResolver = new Resolver() } return builder.build() diff --git a/packages/did-auth-siop-op-authenticator/src/types/IDidAuthSiopOpAuthenticator.ts b/packages/did-auth-siop-op-authenticator/src/types/IDidAuthSiopOpAuthenticator.ts index 09a6b4c65..d2232fe51 100644 --- a/packages/did-auth-siop-op-authenticator/src/types/IDidAuthSiopOpAuthenticator.ts +++ b/packages/did-auth-siop-op-authenticator/src/types/IDidAuthSiopOpAuthenticator.ts @@ -7,6 +7,7 @@ import { IKeyManager, IDataStoreORM, FindCredentialsArgs, + ICredentialIssuer, } from '@veramo/core' import { IPresentation, IVerifiableCredential } from '@sphereon/ssi-types' import { OpSession } from '../session/OpSession' @@ -18,6 +19,7 @@ import { VerifiablePresentationTypeFormat, PresentationSignCallback, } from '@sphereon/did-auth-siop' +import { VerifyCallback } from '@sphereon/wellknown-dids-client' import { Resolvable } from 'did-resolver' @@ -106,6 +108,8 @@ export interface IRegisterSiopSessionArgs { resolver?: Resolvable perDidResolvers?: PerDidResolver[] supportedDidMethods?: string[] + wellKnownDidVerifyCallback: VerifyCallback + presentationSignCallback: PresentationSignCallback sessionId?: string expiresIn?: number } @@ -158,4 +162,4 @@ export enum events { DID_SIOP_AUTHENTICATED = 'didSiopAuthenticated', } -export type IRequiredContext = IAgentContext +export type IRequiredContext = IAgentContext diff --git a/packages/ssi-types/src/mapper/credential-mapper.ts b/packages/ssi-types/src/mapper/credential-mapper.ts index a24f727e7..25342b9bf 100644 --- a/packages/ssi-types/src/mapper/credential-mapper.ts +++ b/packages/ssi-types/src/mapper/credential-mapper.ts @@ -15,7 +15,6 @@ import { import jwt_decode from 'jwt-decode' import { ObjectUtils } from '../utils' - export class CredentialMapper { static decodeVerifiablePresentation(presentation: OriginalVerifiablePresentation): JwtDecodedVerifiablePresentation | IVerifiablePresentation { if (CredentialMapper.isJwtEncoded(presentation)) {