From 4b7e8aecba5825cdee14fe12b50e9dc57f64d9ab Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Wed, 20 Nov 2024 13:13:36 +0100 Subject: [PATCH 01/48] feat: dcql alpha --- package.json | 4 +- .../AuthorizationRequest.ts | 30 ++++-- .../lib/authorization-request/Payload.ts | 18 +++- .../lib/authorization-request/URI.ts | 8 +- .../lib/authorization-request/types.ts | 4 +- .../AuthorizationResponse.ts | 33 ++++--- .../lib/authorization-response/Dcql.ts | 44 +++++++++ .../lib/authorization-response/OpenID4VP.ts | 99 ++++++++++++------- .../PresentationExchange.ts | 4 +- .../lib/authorization-response/types.ts | 16 ++- .../lib/helpers/SIOPSpecVersion.ts | 3 +- packages/siop-oid4vp/lib/op/OP.ts | 34 ++++--- .../siop-oid4vp/lib/request-object/Payload.ts | 1 + packages/siop-oid4vp/lib/rp/RP.ts | 4 + packages/siop-oid4vp/lib/rp/RPBuilder.ts | 18 ++++ packages/siop-oid4vp/lib/types/Errors.ts | 2 +- packages/siop-oid4vp/lib/types/SIOP.types.ts | 7 ++ packages/siop-oid4vp/package.json | 1 + pnpm-lock.yaml | 3 + 19 files changed, 245 insertions(+), 88 deletions(-) create mode 100644 packages/siop-oid4vp/lib/authorization-response/Dcql.ts diff --git a/package.json b/package.json index 35f5b75b..ac994988 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,6 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ] + ], + "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" } - diff --git a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts index 13316a70..aeb4b15b 100644 --- a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts +++ b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts @@ -1,6 +1,8 @@ import { parseJWT } from '@sphereon/oid4vc-common' +import { DcqlQuery } from 'dcql' import { PresentationDefinitionWithLocation } from '../authorization-response' +import { findValidDcqlQuery } from '../authorization-response/Dcql' import { PresentationExchange } from '../authorization-response/PresentationExchange' import { fetchByReferenceOrUseByValue, removeNullUndefined } from '../helpers' import { authorizationRequestVersionDiscovery } from '../helpers/SIOPSpecVersion' @@ -66,7 +68,7 @@ export class AuthorizationRequest { const requestObjectArg = opts.requestObject.passBy !== PassBy.NONE ? (requestObject ? requestObject : await RequestObject.fromOpts(opts)) : undefined - // opts?.payload was removed before, but it's not clear atm why opts?.payload was removed + // opts?.payload was removed before, but it's not clear atm why opts?.payload was removed const requestPayload = opts?.payload ? await createAuthorizationRequestPayload(opts, requestObjectArg) : undefined return new AuthorizationRequest(requestPayload, requestObjectArg, opts) } @@ -190,14 +192,22 @@ export class AuthorizationRequest { // TODO see if this is too naive. The OpenID conformance test explicitly tests for this // But the spec says: The client_id and client_id_scheme MUST be omitted in unsigned requests defined in Appendix A.3.1. // So I would expect client_id_scheme and client_id to be undefined when the JWT header has alg: none - if(mergedPayload.client_id && mergedPayload.client_id_scheme === 'redirect_uri' && mergedPayload.client_id !== responseURI) { - throw Error(`${SIOPErrors.INVALID_REQUEST}, response_uri does not match the client_id provided by the verifier which is required for client_id_scheme redirect_uri`) + if (mergedPayload.client_id && mergedPayload.client_id_scheme === 'redirect_uri' && mergedPayload.client_id !== responseURI) { + throw Error( + `${SIOPErrors.INVALID_REQUEST}, response_uri does not match the client_id provided by the verifier which is required for client_id_scheme redirect_uri`, + ) } - + // TODO: we need to verify somewhere that if response_mode is direct_post, that the response_uri may be present, // BUT not both redirect_uri and response_uri. What is the best place to do this? - const presentationDefinitions: PresentationDefinitionWithLocation[] = await PresentationExchange.findValidPresentationDefinitions(mergedPayload, await this.getSupportedVersion()) + const presentationDefinitions: PresentationDefinitionWithLocation[] = await PresentationExchange.findValidPresentationDefinitions( + mergedPayload, + await this.getSupportedVersion(), + ) + + const dcqlQuery = await findValidDcqlQuery(mergedPayload) + return { jwt, payload: parsedJwt?.payload, @@ -208,6 +218,7 @@ export class AuthorizationRequest { correlationId: opts.correlationId, authorizationRequest: this, verifyOpts: opts, + dcqlQuery, presentationDefinitions, registrationMetadataPayload, requestObject: this.requestObject, @@ -267,8 +278,9 @@ export class AuthorizationRequest { } public async mergedPayloads(): Promise { - const requestObjectPayload = { ...this.payload, ...(this.requestObject && (await this.requestObject.getPayload())) } - if (requestObjectPayload.scope && typeof requestObjectPayload.scope !== 'string') { // test mattr.launchpad.spec.ts does not supply a scope value + const requestObjectPayload = { ...this.payload, ...(this.requestObject && (await this.requestObject.getPayload())) } + if (requestObjectPayload.scope && typeof requestObjectPayload.scope !== 'string') { + // test mattr.launchpad.spec.ts does not supply a scope value throw new Error('Invalid scope value') } return requestObjectPayload as RequestObjectPayload @@ -277,4 +289,8 @@ export class AuthorizationRequest { public async getPresentationDefinitions(version?: SupportedVersion): Promise { return await PresentationExchange.findValidPresentationDefinitions(await this.mergedPayloads(), version) } + + public async getDcqlQuery(): Promise { + return await findValidDcqlQuery(await this.mergedPayloads()) + } } diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index 3219f700..b21d7c70 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -18,20 +18,28 @@ import { createRequestRegistration } from './RequestRegistration' import { ClaimPayloadOptsVID1, CreateAuthorizationRequestOpts, PropertyTarget } from './types' export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadOptsVID1): ClaimPayloadVID1 => { - if (!opts || !opts.vp_token || (!opts.vp_token.presentation_definition && !opts.vp_token.presentation_definition_uri)) { + if ( + !opts || + !opts.vp_token || + (!opts.vp_token.presentation_definition && !opts.vp_token.presentation_definition_uri && !opts.vp_token.dcql_query) + ) { return undefined } - const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) - if (discoveryResult.error) { - throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) + + if (opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri) { + const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) + if (discoveryResult.error) { + throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) + } } return { ...(opts.id_token ? { id_token: opts.id_token } : {}), - ...((opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri) && { + ...((opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri || opts.vp_token.dcql_query) && { vp_token: { ...(!opts.vp_token.presentation_definition_uri && { presentation_definition: opts.vp_token.presentation_definition }), ...(opts.vp_token.presentation_definition_uri && { presentation_definition_uri: opts.vp_token.presentation_definition_uri }), + ...(opts.vp_token.dcql_query && { dcql_query: opts.vp_token.dcql_query }), }, }), } diff --git a/packages/siop-oid4vp/lib/authorization-request/URI.ts b/packages/siop-oid4vp/lib/authorization-request/URI.ts index 7aa04815..f6bf42bc 100644 --- a/packages/siop-oid4vp/lib/authorization-request/URI.ts +++ b/packages/siop-oid4vp/lib/authorization-request/URI.ts @@ -1,5 +1,6 @@ import { parseJWT } from '@sphereon/oid4vc-common' +import { findValidDcqlQuery } from '../authorization-response/Dcql' import { PresentationExchange } from '../authorization-response/PresentationExchange' import { decodeUriAsJson, encodeJsonAsURI, fetchByReferenceOrUseByValue } from '../helpers' import { assertValidRequestObjectPayload, RequestObject } from '../request-object' @@ -126,7 +127,6 @@ export class URI implements AuthorizationRequestURI { ...authorizationRequest.options.requestObject, version: authorizationRequest.options.version, uriScheme: authorizationRequest.options.uriScheme, - }, authorizationRequest.payload, authorizationRequest.requestObject, @@ -164,8 +164,9 @@ export class URI implements AuthorizationRequestURI { const requestObjectPayload: RequestObjectPayload = requestObjectJwt ? (parseJWT(requestObjectJwt).payload as RequestObjectPayload) : undefined if (requestObjectPayload) { - // Only used to validate if the request object contains presentation definition(s) + // Only used to validate if the request object contains presentation definition(s) | a dcql query await PresentationExchange.findValidPresentationDefinitions({ ...authorizationRequestPayload, ...requestObjectPayload }) + await findValidDcqlQuery({ ...authorizationRequestPayload, ...requestObjectPayload }) assertValidRequestObjectPayload(requestObjectPayload) if (requestObjectPayload.registration) { @@ -194,7 +195,8 @@ export class URI implements AuthorizationRequestURI { } } else { try { - scheme = (await authorizationRequest.getSupportedVersion()) === SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1 ? 'openid-vc://' : 'openid4vp://' + scheme = + (await authorizationRequest.getSupportedVersion()) === SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1 ? 'openid-vc://' : 'openid4vp://' } catch (error: unknown) { scheme = 'openid4vp://' } diff --git a/packages/siop-oid4vp/lib/authorization-request/types.ts b/packages/siop-oid4vp/lib/authorization-request/types.ts index 64956db9..da1abd0c 100644 --- a/packages/siop-oid4vp/lib/authorization-request/types.ts +++ b/packages/siop-oid4vp/lib/authorization-request/types.ts @@ -1,7 +1,7 @@ import { SigningAlgo } from '@sphereon/oid4vc-common' import { Hasher } from '@sphereon/ssi-types' -import { PresentationDefinitionPayloadOpts } from '../authorization-response' +import { DcqlQueryPayloadOpts, PresentationDefinitionPayloadOpts } from '../authorization-response' import { RequestObjectOpts } from '../request-object' import { ClientIdScheme, @@ -19,7 +19,7 @@ import { VerifyJwtCallback } from '../types/VpJwtVerifier' export interface ClaimPayloadOptsVID1 extends ClaimPayloadCommonOpts { id_token?: IdTokenClaimPayload - vp_token?: PresentationDefinitionPayloadOpts + vp_token?: PresentationDefinitionPayloadOpts | DcqlQueryPayloadOpts } export interface ClaimPayloadCommonOpts { diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 64c3cc54..de5f1b3a 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -124,21 +124,25 @@ export class AuthorizationResponse { }) if (hasVpToken) { - const wrappedPresentations = response.payload.vp_token - ? await extractPresentationsFromVpToken(response.payload.vp_token, { + if (responseOpts.presentationExchange) { + const wrappedPresentations = response.payload.vp_token + ? await extractPresentationsFromVpToken(response.payload.vp_token, { + hasher: verifyOpts.hasher, + }) + : [] + + await assertValidVerifiablePresentations({ + presentationDefinitions, + presentations: wrappedPresentations, + verificationCallback: verifyOpts.verification.presentationVerificationCallback, + opts: { + ...responseOpts.presentationExchange, hasher: verifyOpts.hasher, - }) - : [] - - await assertValidVerifiablePresentations({ - presentationDefinitions, - presentations: wrappedPresentations, - verificationCallback: verifyOpts.verification.presentationVerificationCallback, - opts: { - ...responseOpts.presentationExchange, - hasher: verifyOpts.hasher, - }, - }) + }, + }) + } else { + throw new Error('TODO: VALIDATE PRESENTATION AGAINST DEFINITION') + } } return response @@ -219,7 +223,6 @@ export class AuthorizationResponse { } const presentationsArray = Array.isArray(presentations) ? presentations : [presentations] - // We do not verify them, as that is done elsewhere. So we simply can take the first nonce nonce = presentationsArray // FIXME toWrappedVerifiablePresentation() does not extract the nonce yet from mdocs. diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts new file mode 100644 index 00000000..e67fb783 --- /dev/null +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -0,0 +1,44 @@ +import { DcqlQuery } from 'dcql' + +import { extractDataFromPath } from '../helpers' +import { AuthorizationRequestPayload, SIOPErrors } from '../types' + +/** + * Finds a valid DcqlQuery inside the given AuthenticationRequestPayload + * throws exception if the DcqlQuery is not valid + * returns the decoded dcql query if a valid instance found + * @param authorizationRequestPayload object that can have a dcql_query inside + * @param version + */ +export const findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise => { + const vpTokens: string[] = extractDataFromPath(authorizationRequestPayload, '$..vp_token.dcql_query').map((d) => d.value) + const vpTokensList: string[] = extractDataFromPath(authorizationRequestPayload, '$..vp_token.dcql_query[*]').map((d) => d.value) + const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition') + const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]') + const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri') + const definitionRefsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri[*]') + + const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) + const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) + const hasDcql = (vpTokens && vpTokens.length > 0) || (vpTokensList && vpTokensList.length > 0) + + if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) { + throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) + } + + if (!(vpTokens && vpTokens.length) && !(vpTokensList && vpTokensList.length)) { + throw new Error('Cannot find dcql_query in vp_token. Presentation definition is present') + } + + if (vpTokens.length > 1 && vpTokensList.length > 1) { + throw new Error('Found multiple dcql_query in vp_token. Only one is allowed') + } + + const encoded = vpTokens.length ? vpTokens[0] : vpTokensList[0] + if (!encoded) return undefined + + const dcqlQuery = DcqlQuery.parse(JSON.parse(encoded)) + DcqlQuery.validate(dcqlQuery) + + return dcqlQuery +} diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 0db13b81..ec76bd4d 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -10,6 +10,7 @@ import { W3CVerifiablePresentation, WrappedVerifiablePresentation, } from '@sphereon/ssi-types' +import { DcqlQuery, DcqlQueryVpToken } from 'dcql' import { AuthorizationRequest } from '../authorization-request' import { verifyRevocation } from '../helpers' @@ -70,46 +71,76 @@ export const verifyPresentations = async ( authorizationResponse: AuthorizationResponse, verifyOpts: VerifyAuthorizationResponseOpts, ): Promise => { - if (!authorizationResponse.payload.vp_token || Array.isArray(authorizationResponse.payload.vp_token) && authorizationResponse.payload.vp_token.length === 0) { + if ( + !authorizationResponse.payload.vp_token || + (Array.isArray(authorizationResponse.payload.vp_token) && authorizationResponse.payload.vp_token.length === 0) + ) { return Promise.reject(Error('the payload is missing a vp_token')) } - - const presentations = await extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) - const presentationDefinitions = verifyOpts.presentationDefinitions - ? Array.isArray(verifyOpts.presentationDefinitions) - ? verifyOpts.presentationDefinitions - : [verifyOpts.presentationDefinitions] - : [] + let idPayload: IDTokenPayload | undefined if (authorizationResponse.idToken) { idPayload = await authorizationResponse.idToken.payload() } + // todo: Probably wise to check against request for the location of the submission_data const presentationSubmission = idPayload?._vp_token?.presentation_submission ?? authorizationResponse.payload.presentation_submission - await assertValidVerifiablePresentations({ - presentationDefinitions, - presentations, - verificationCallback: verifyOpts.verification.presentationVerificationCallback, - opts: { - presentationSubmission, - restrictToFormats: verifyOpts.restrictToFormats, - restrictToDIDMethods: verifyOpts.restrictToDIDMethods, - hasher: verifyOpts.hasher, - }, - }) + let wrappedPresentations: WrappedVerifiablePresentation[] = [] + const presentationDefinitions = verifyOpts.presentationDefinitions + ? Array.isArray(verifyOpts.presentationDefinitions) + ? verifyOpts.presentationDefinitions + : [verifyOpts.presentationDefinitions] + : [] + + const dcqlQuery = verifyOpts.dcqlQuery ?? authorizationResponse.authorizationRequest.payload.dcql_query + if (dcqlQuery) { + const dcqlQueryVpToken = DcqlQueryVpToken.parse(JSON.parse(authorizationResponse.payload.vp_token as string)) + + const parsedQuery = DcqlQuery.parse(dcqlQuery) + DcqlQuery.validate(parsedQuery) + + const presentations = Object.values(dcqlQueryVpToken) as Array + wrappedPresentations = presentations.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: verifyOpts.hasher })) + + const verifiedPresentations = await Promise.all( + presentations.map((presentation) => verifyOpts.verification.presentationVerificationCallback(presentation, presentationSubmission)), + ) + + // TODO: assert the submission against the definition + + if (verifiedPresentations.some((verified) => !verified)) { + const message = verifiedPresentations + .map((verified) => verified.reason) + .filter(Boolean) + .join(', ') + + throw Error(`Failed to verify presentations. ${message}`) + } + } else { + const presentations = await extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) + wrappedPresentations = Array.isArray(presentations) ? presentations : [presentations] + + await assertValidVerifiablePresentations({ + presentationDefinitions, + presentations, + verificationCallback: verifyOpts.verification.presentationVerificationCallback, + opts: { + presentationSubmission, + restrictToFormats: verifyOpts.restrictToFormats, + restrictToDIDMethods: verifyOpts.restrictToDIDMethods, + hasher: verifyOpts.hasher, + }, + }) + } // If there are no presentations, and the `assertValidVerifiablePresentations` did not fail // it means there's no oid4vp response and also not requested - if (Array.isArray(presentations) && presentations.length === 0) { + if (wrappedPresentations.length === 0) { return null } - if (!presentations || (Array.isArray(presentations) && presentations.length === 0)) { - return Promise.reject(Error('missing presentation(s)')) - } - const presentationsArray = Array.isArray(presentations) ? presentations : [presentations] - const presentationsWithoutMdoc = presentationsArray.filter((p) => p.format !== 'mso_mdoc') + const presentationsWithoutMdoc = wrappedPresentations.filter((p) => p.format !== 'mso_mdoc') const nonces = new Set(presentationsWithoutMdoc.map(extractNonceFromWrappedVerifiablePresentation)) if (presentationsWithoutMdoc.length > 0 && nonces.size !== 1) { throw Error(`${nonces.size} nonce values found for ${presentationsWithoutMdoc.length}. Should be 1`) @@ -128,24 +159,22 @@ export const verifyPresentations = async ( if (!verifyOpts.verification.revocationOpts?.revocationVerificationCallback) { throw Error(`Please provide a revocation callback as revocation checking of credentials and presentations is not disabled`) } - for (const vp of presentationsArray) { + for (const vp of wrappedPresentations) { await verifyRevocation(vp, verifyOpts.verification.revocationOpts.revocationVerificationCallback, revocationVerification) } } - return { nonce, presentations: presentationsArray, presentationDefinitions, submissionData: presentationSubmission } + return { nonce, presentations: wrappedPresentations, presentationDefinitions, submissionData: presentationSubmission } } export const extractPresentationsFromVpToken = async ( vpToken: Array | W3CVerifiablePresentation | CompactSdJwtVc | string, opts?: { hasher?: Hasher }, ): Promise => { - const tokens = Array.isArray(vpToken) ? vpToken : [vpToken]; - const wrappedTokens = tokens.map(vp => - CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: opts?.hasher }) - ); + const tokens = Array.isArray(vpToken) ? vpToken : [vpToken] + const wrappedTokens = tokens.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: opts?.hasher })) - return tokens.length === 1 ? wrappedTokens[0] : wrappedTokens; - } + return tokens.length === 1 ? wrappedTokens[0] : wrappedTokens +} export const createPresentationSubmission = async ( verifiablePresentations: W3CVerifiablePresentation[], @@ -285,8 +314,8 @@ export const assertValidVerifiablePresentations = async (args: { presentationSubmission?: PresentationSubmission hasher?: Hasher } -}) : Promise => { - const {presentations} = args +}): Promise => { + const { presentations } = args if (!presentations || (Array.isArray(presentations) && presentations.length === 0)) { return Promise.reject(Error('missing presentation(s)')) } diff --git a/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts b/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts index 18764cb1..cae54fb5 100644 --- a/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts +++ b/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts @@ -195,7 +195,7 @@ export class PresentationExchange { ).map((d) => d.value) const vpTokenRefs = extractDataFromPath(authorizationRequestPayload, '$..vp_token.presentation_definition_uri') if (vpTokens && vpTokens.length && vpTokenRefs && vpTokenRefs.length) { - throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_BY_REF_AND_VALUE_NON_EXCLUSIVE) + throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) } if (vpTokens && vpTokens.length) { vpTokens.forEach((vpToken: PresentationDefinitionV1 | PresentationDefinitionV2) => { @@ -252,7 +252,7 @@ export class PresentationExchange { const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) if (hasPD && hasPdRef) { - throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_BY_REF_AND_VALUE_NON_EXCLUSIVE) + throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) } if (definitions && definitions.length > 0) { definitions.forEach((definition) => { diff --git a/packages/siop-oid4vp/lib/authorization-response/types.ts b/packages/siop-oid4vp/lib/authorization-response/types.ts index 9ec19ddc..9a6e1bf2 100644 --- a/packages/siop-oid4vp/lib/authorization-response/types.ts +++ b/packages/siop-oid4vp/lib/authorization-response/types.ts @@ -5,10 +5,11 @@ import { CompactSdJwtVc, Hasher, MdocOid4vpIssuerSigned, + MdocOid4vpMdocVpToken, PresentationSubmission, W3CVerifiablePresentation, - MdocOid4vpMdocVpToken, } from '@sphereon/ssi-types' +import { DcqlQuery, DcqlQueryVpToken } from 'dcql' import { ResponseMode, @@ -41,6 +42,7 @@ export interface AuthorizationResponseOpts { tokenType?: string refreshToken?: string presentationExchange?: PresentationExchangeResponseOpts + dcqlQuery?: DcqlQueryResponseOpts } export interface PresentationExchangeResponseOpts { @@ -59,6 +61,10 @@ export interface PresentationExchangeResponseOpts { restrictToDIDMethods?: string[] } +export interface DcqlQueryResponseOpts { + credentialQueryIdToPresentation: DcqlQueryVpToken +} + export interface PresentationExchangeRequestOpts { presentationVerificationCallback?: PresentationVerificationCallback } @@ -66,6 +72,13 @@ export interface PresentationExchangeRequestOpts { export interface PresentationDefinitionPayloadOpts { presentation_definition?: IPresentationDefinition presentation_definition_uri?: string + dcql_query?: never +} + +export interface DcqlQueryPayloadOpts { + dcql_query?: string + presentation_definition?: never + presentation_definition_uri?: never } export interface PresentationDefinitionWithLocation { @@ -108,6 +121,7 @@ export interface VerifyAuthorizationResponseOpts { nonce?: string // To verify the response against the supplied nonce state?: string // To verify the response against the supplied state presentationDefinitions?: PresentationDefinitionWithLocation | PresentationDefinitionWithLocation[] // The presentation definitions to match against VPs in the response + dcqlQuery?: DcqlQuery audience?: string // The audience/redirect_uri restrictToFormats?: Format // Further restrict to certain VC formats, not expressed in the presentation definition restrictToDIDMethods?: string[] diff --git a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts index 2e0d9d77..5e41e4e8 100644 --- a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts +++ b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts @@ -29,7 +29,8 @@ function isID1Payload(authorizationRequest: AuthorizationRequestPayload) { !authorizationRequest.client_metadata_uri && !authorizationRequest.client_metadata && !authorizationRequest.presentation_definition && - !authorizationRequest.presentation_definition_uri + !authorizationRequest.presentation_definition_uri && + !authorizationRequest.dcql_query ) } diff --git a/packages/siop-oid4vp/lib/op/OP.ts b/packages/siop-oid4vp/lib/op/OP.ts index 7fee9a0a..e4fa29fb 100644 --- a/packages/siop-oid4vp/lib/op/OP.ts +++ b/packages/siop-oid4vp/lib/op/OP.ts @@ -1,15 +1,16 @@ -import { EventEmitter } from 'events'; +import { EventEmitter } from 'events' import { jarmAuthResponseSend, JarmClientMetadata, jarmMetadataValidate, JarmServerMetadata } from '@sphereon/jarm' -import { JwtIssuer, uuidv4 } from '@sphereon/oid4vc-common'; -import { IIssuerId } from '@sphereon/ssi-types'; +import { JwtIssuer, uuidv4 } from '@sphereon/oid4vc-common' +import { IIssuerId } from '@sphereon/ssi-types' -import { AuthorizationRequest, URI, VerifyAuthorizationRequestOpts } from '../authorization-request'; -import { mergeVerificationOpts } from '../authorization-request/Opts'; +import { AuthorizationRequest, URI, VerifyAuthorizationRequestOpts } from '../authorization-request' +import { mergeVerificationOpts } from '../authorization-request/Opts' import { AuthorizationResponse, AuthorizationResponseOpts, AuthorizationResponseWithCorrelationId, + DcqlQueryResponseOpts, PresentationExchangeResponseOpts, } from '../authorization-response' import { encodeJsonAsURI, post } from '../helpers' @@ -29,11 +30,11 @@ import { SupportedVersion, UrlEncodingFormat, Verification, - VerifiedAuthorizationRequest -} from '../types'; + VerifiedAuthorizationRequest, +} from '../types' -import { OPBuilder } from './OPBuilder'; -import { createResponseOptsFromBuilderOrExistingOpts, createVerifyRequestOptsFromBuilderOrExistingOpts } from './Opts'; +import { OPBuilder } from './OPBuilder' +import { createResponseOptsFromBuilderOrExistingOpts, createVerifyRequestOptsFromBuilderOrExistingOpts } from './Opts' // The OP publishes the formats it supports using the vp_formats_supported metadata parameter as defined above in its "openid-configuration". export class OP { @@ -78,7 +79,7 @@ export class OP { try { const verifiedAuthorizationRequest = await authorizationRequest.verify( - this.newVerifyAuthorizationRequestOpts({ ...requestOpts, correlationId }) + this.newVerifyAuthorizationRequestOpts({ ...requestOpts, correlationId }), ) await this.emitEvent(AuthorizationEvents.ON_AUTH_REQUEST_VERIFIED_SUCCESS, { @@ -106,6 +107,7 @@ export class OP { issuer?: ResponseIss | string verification?: Verification presentationExchange?: PresentationExchangeResponseOpts + dcqlQuery?: DcqlQueryResponseOpts }, ): Promise { if ( @@ -235,7 +237,7 @@ export class OP { const { response } = await createJarmResponse({ requestObjectPayload, authorizationResponsePayload: payload, - clientMetadata + clientMetadata, }) try { @@ -243,9 +245,9 @@ export class OP { authRequestParams: { response_uri: responseUri, response_mode: responseMode, - response_type: responseType + response_type: responseType, }, - authResponse: response + authResponse: response, }) void this.emitEvent(AuthorizationEvents.ON_AUTH_RESPONSE_SENT_SUCCESS, { correlationId, subject: response }) return jarmResponse @@ -253,7 +255,7 @@ export class OP { void this.emitEvent(AuthorizationEvents.ON_AUTH_RESPONSE_SENT_FAILED, { correlationId, subject: response, - error + error, }) throw error } @@ -294,6 +296,7 @@ export class OP { issuer?: IIssuerId | ResponseIss audience?: string presentationExchange?: PresentationExchangeResponseOpts + dcqlQuery?: DcqlQueryResponseOpts }): AuthorizationResponseOpts { const version = opts.version ?? this._createResponseOptions.version let issuer = opts.issuer ?? this._createResponseOptions?.registration?.issuer @@ -308,11 +311,14 @@ export class OP { } // We are taking the whole presentationExchange object from a certain location const presentationExchange = opts.presentationExchange ?? this._createResponseOptions.presentationExchange + const dcqlQuery = opts.dcqlQuery ?? this._createResponseOptions.dcqlQuery + const responseURI = opts.audience ?? this._createResponseOptions.responseURI return { ...this._createResponseOptions, ...opts, ...(presentationExchange && { presentationExchange }), + ...(dcqlQuery && { dcqlQuery }), registration: { ...this._createResponseOptions?.registration, issuer }, responseURI, responseURIType: diff --git a/packages/siop-oid4vp/lib/request-object/Payload.ts b/packages/siop-oid4vp/lib/request-object/Payload.ts index 59991031..661c7ee3 100644 --- a/packages/siop-oid4vp/lib/request-object/Payload.ts +++ b/packages/siop-oid4vp/lib/request-object/Payload.ts @@ -48,6 +48,7 @@ export const createRequestObjectPayload = async (opts: CreateAuthorizationReques claims, presentation_definition_uri: payload.presentation_definition_uri, presentation_definition: payload.presentation_definition, + dcql_query: payload.dcql_query, client_metadata: payload.client_metadata, iat, nbf, diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index d165dac2..addc9a23 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -8,6 +8,7 @@ import { } from '@sphereon/jarm' import { decodeProtectedHeader, JwtIssuer, uuidv4 } from '@sphereon/oid4vc-common' import { Hasher } from '@sphereon/ssi-types' +import { DcqlQuery } from 'dcql' import { AuthorizationRequest, @@ -202,6 +203,7 @@ export class RP { nonce?: string verification?: Verification presentationDefinitions?: PresentationDefinitionWithLocation | PresentationDefinitionWithLocation[] + dcqlQuery?: DcqlQuery }, ): Promise { const state = opts?.state || this.verifyResponseOptions.state @@ -376,6 +378,7 @@ export class RP { verification?: Verification audience?: string presentationDefinitions?: PresentationDefinitionWithLocation | PresentationDefinitionWithLocation[] + dcqlQuery?: DcqlQuery }, ): Promise { let correlationId = opts?.correlationId ?? this._verifyResponseOptions.correlationId @@ -418,6 +421,7 @@ export class RP { nonce, verification: mergeVerificationOpts(this._verifyResponseOptions, opts), presentationDefinitions: opts?.presentationDefinitions ?? this._verifyResponseOptions.presentationDefinitions, + dcqlQuery: opts?.dcqlQuery ?? this._verifyResponseOptions.dcqlQuery, } } diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index fbbdec63..c27b01b1 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -218,6 +218,24 @@ export class RPBuilder { return this } + withDcqlQuery(dcqlQuery: string, targets?: PropertyTargets): RPBuilder { + this._authorizationRequestPayload.dcql_query = assignIfAuth( + { + propertyValue: dcqlQuery, + targets, + }, + false, + ) + this._requestObjectPayload.dcql_query = assignIfRequestObject( + { + propertyValue: dcqlQuery, + targets, + }, + true, + ) + return this + } + withPresentationDefinition(definitionOpts: { definition: IPresentationDefinition; definitionUri?: string }, targets?: PropertyTargets): RPBuilder { const { definition, definitionUri } = definitionOpts diff --git a/packages/siop-oid4vp/lib/types/Errors.ts b/packages/siop-oid4vp/lib/types/Errors.ts index 24c36f92..780d8c17 100644 --- a/packages/siop-oid4vp/lib/types/Errors.ts +++ b/packages/siop-oid4vp/lib/types/Errors.ts @@ -38,7 +38,7 @@ enum SIOPErrors { REFERENCE_URI_NO_PAYLOAD = 'referenceUri specified, but object to host there is not present', NO_SELF_ISSUED_ISS = 'The Response Token Issuer Claim (iss) MUST start with https://self-isued.me/v2', REGISTRATION_NOT_SET = 'Registration metadata not set.', - REQUEST_CLAIMS_PRESENTATION_DEFINITION_BY_REF_AND_VALUE_NON_EXCLUSIVE = "Request claims can't have both 'presentation_definition' and 'presentation_definition_uri'", + REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE = "Request claims can't multiple of 'presentation_definition' and 'presentation_definition_uri' 'dcql_query", REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID = 'Presentation definition in the request claims is not valid', REQUEST_OBJECT_TYPE_NOT_SET = 'Request object type is not set.', RESPONSE_OPTS_PRESENTATIONS_SUBMISSION_IS_NOT_VALID = 'presentation_submission object inside the response opts vp should be valid', diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index a104d0b7..30619c0f 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -13,6 +13,7 @@ import { W3CVerifiablePresentation, WrappedVerifiablePresentation, } from '@sphereon/ssi-types' +import { DcqlQuery } from 'dcql' import { AuthorizationRequest, CreateAuthorizationRequestOpts, PropertyTargets, VerifyAuthorizationRequestOpts } from '../authorization-request' import { @@ -98,6 +99,7 @@ export interface AuthorizationRequestPayloadVD12OID4VPD20 presentation_definition_uri?: string client_id_scheme?: ClientIdSchemeOID4VPD20 response_uri?: string // New since OID4VP18 OPTIONAL. The Response URI to which the Wallet MUST send the Authorization Response using an HTTPS POST request as defined by the Response Mode direct_post. The Response URI receives all Authorization Response parameters as defined by the respective Response Type. When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error. + dcql_query?: string } export type ClientIdSchemeOID4VPD18 = 'pre-registered' | 'redirect_uri' | 'entity_id' | 'did' @@ -139,6 +141,7 @@ export interface VerifiedAuthorizationRequest extends Partial { requestObject?: RequestObject // The Request object registrationMetadataPayload: RPRegistrationMetadataPayload presentationDefinitions?: PresentationDefinitionWithLocation[] // The optional presentation definition objects that the RP requests + dcqlQuery?: DcqlQuery verifyOpts: VerifyAuthorizationRequestOpts // The verification options for the authentication request versions: SupportedVersion[] } @@ -164,6 +167,8 @@ export interface IDTokenPayload extends JWTPayload { } } +export type DcqlQueryVpToken = string + export interface AuthorizationResponsePayload { access_token?: string token_type?: string @@ -176,6 +181,7 @@ export interface AuthorizationResponsePayload { | W3CVerifiablePresentation | CompactSdJwtVc | MdocOid4vpMdocVpToken + | DcqlQueryVpToken presentation_submission?: PresentationSubmission verifiedData?: IPresentation | AdditionalClaims // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -190,6 +196,7 @@ export interface IdTokenClaimPayload { export interface VpTokenClaimPayload { presentation_definition?: PresentationDefinitionV1 | PresentationDefinitionV2 presentation_definition_uri?: string + dcql_query?: string } export interface ClaimPayloadCommon { diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index bc687cf5..ad8ea863 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,6 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", + "dcql": "link:../../../dcql/dcql", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.129", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7378a309..b16db23d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -460,6 +460,9 @@ importers: cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) + dcql: + specifier: link:../../../dcql/dcql + version: link:../../../dcql/dcql debug: specifier: ^4.3.5 version: 4.3.7 From dc1c318fa130dc7fec493b82f69a1f563f62713c Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Thu, 21 Nov 2024 08:31:10 +0100 Subject: [PATCH 02/48] feat: dcql alpha --- .../AuthorizationResponse.ts | 19 ++++-- .../lib/authorization-response/Dcql.ts | 20 +++--- .../lib/authorization-response/OpenID4VP.ts | 62 +++++++++++-------- .../lib/authorization-response/Payload.ts | 6 +- .../lib/authorization-response/types.ts | 6 +- packages/siop-oid4vp/lib/rp/RP.ts | 6 +- ...ationRequestPayloadVD12OID4VPD20.schema.ts | 3 + .../AuthorizationRequestPayloadVID1.schema.ts | 3 + .../AuthorizationResponseOpts.schema.ts | 26 ++++++++ packages/siop-oid4vp/lib/types/SIOP.types.ts | 7 +++ 10 files changed, 111 insertions(+), 47 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index de5f1b3a..df4d1288 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -1,4 +1,4 @@ -import { CredentialMapper, Hasher } from '@sphereon/ssi-types' +import { CredentialMapper, Hasher, WrappedVerifiablePresentation } from '@sphereon/ssi-types' import { AuthorizationRequest, VerifyAuthorizationRequestOpts } from '../authorization-request' import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-request/Opts' @@ -11,6 +11,7 @@ import { extractPresentationsFromVpToken, verifyPresentations, } from './OpenID4VP' +import { extractPresentationsFromDcqlVpToken } from './OpenID4VP' import { assertValidResponseOpts } from './Opts' import { createResponsePayload } from './Payload' import { AuthorizationResponseOpts, PresentationDefinitionWithLocation, VerifyAuthorizationResponseOpts } from './types' @@ -141,7 +142,7 @@ export class AuthorizationResponse { }, }) } else { - throw new Error('TODO: VALIDATE PRESENTATION AGAINST DEFINITION') + console.error('TODO: VALIDATE PRESENTATION AGAINST DEFINITION') } } @@ -189,7 +190,8 @@ export class AuthorizationResponse { state, correlationId: verifyOpts.correlationId, ...(this.idToken && { idToken: verifiedIdToken }), - ...(oid4vp && { oid4vpSubmission: oid4vp }), + ...(oid4vp && 'presentationDefinitions' in oid4vp && { oid4vpSubmission: oid4vp }), + ...(oid4vp && 'dcqlQuery' in oid4vp && { oid4vpSubmissionDcql: oid4vp }), } } @@ -217,8 +219,15 @@ export class AuthorizationResponse { public async mergedPayloads(opts?: { consistencyCheck?: boolean; hasher?: Hasher }): Promise { let nonce: string | undefined = this._payload.nonce if (this._payload?.vp_token) { - const presentations = this.payload.vp_token ? await extractPresentationsFromVpToken(this.payload.vp_token, opts) : [] - if (!presentations || (Array.isArray(presentations) && presentations.length === 0)) { + let presentations: WrappedVerifiablePresentation | WrappedVerifiablePresentation[] + + try { + presentations = extractPresentationsFromDcqlVpToken(this._payload.vp_token as string, opts) + } catch (e) { + presentations = extractPresentationsFromVpToken(this._payload.vp_token, opts) + } + + if (presentations && Array.isArray(presentations) && presentations.length === 0) { return Promise.reject(Error('missing presentation(s)')) } const presentationsArray = Array.isArray(presentations) ? presentations : [presentations] diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index e67fb783..16cf9672 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -11,8 +11,8 @@ import { AuthorizationRequestPayload, SIOPErrors } from '../types' * @param version */ export const findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise => { - const vpTokens: string[] = extractDataFromPath(authorizationRequestPayload, '$..vp_token.dcql_query').map((d) => d.value) - const vpTokensList: string[] = extractDataFromPath(authorizationRequestPayload, '$..vp_token.dcql_query[*]').map((d) => d.value) + const dcqlQuery: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query').map((d) => d.value) + const dcqlQueryList: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query[*]').map((d) => d.value) const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition') const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]') const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri') @@ -20,25 +20,21 @@ export const findValidDcqlQuery = async (authorizationRequestPayload: Authorizat const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) - const hasDcql = (vpTokens && vpTokens.length > 0) || (vpTokensList && vpTokensList.length > 0) + const hasDcql = (dcqlQuery && dcqlQuery.length > 0) || (dcqlQueryList && dcqlQueryList.length > 0) if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) { throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) } - if (!(vpTokens && vpTokens.length) && !(vpTokensList && vpTokensList.length)) { - throw new Error('Cannot find dcql_query in vp_token. Presentation definition is present') - } - - if (vpTokens.length > 1 && vpTokensList.length > 1) { + if (dcqlQuery.length > 1 || dcqlQueryList.length > 1) { throw new Error('Found multiple dcql_query in vp_token. Only one is allowed') } - const encoded = vpTokens.length ? vpTokens[0] : vpTokensList[0] + const encoded = dcqlQuery.length ? dcqlQuery[0] : dcqlQueryList[0] if (!encoded) return undefined - const dcqlQuery = DcqlQuery.parse(JSON.parse(encoded)) - DcqlQuery.validate(dcqlQuery) + const parsedDcqlQuery = DcqlQuery.parse(JSON.parse(encoded)) + DcqlQuery.validate(parsedDcqlQuery) - return dcqlQuery + return parsedDcqlQuery } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index ec76bd4d..4ff909cf 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -10,7 +10,7 @@ import { W3CVerifiablePresentation, WrappedVerifiablePresentation, } from '@sphereon/ssi-types' -import { DcqlQuery, DcqlQueryVpToken } from 'dcql' +import { DcqlQuery, DcqlVpToken } from 'dcql' import { AuthorizationRequest } from '../authorization-request' import { verifyRevocation } from '../helpers' @@ -22,6 +22,7 @@ import { SIOPErrors, SupportedVersion, VerifiedOpenID4VPSubmission, + VerifiedOpenID4VPSubmissionDcql, } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' @@ -70,10 +71,12 @@ export const extractNonceFromWrappedVerifiablePresentation = (wrappedVp: Wrapped export const verifyPresentations = async ( authorizationResponse: AuthorizationResponse, verifyOpts: VerifyAuthorizationResponseOpts, -): Promise => { +): Promise => { + if (!authorizationResponse.payload.vp_token) return null if ( - !authorizationResponse.payload.vp_token || - (Array.isArray(authorizationResponse.payload.vp_token) && authorizationResponse.payload.vp_token.length === 0) + authorizationResponse.payload.vp_token && + Array.isArray(authorizationResponse.payload.vp_token) && + authorizationResponse.payload.vp_token.length === 0 ) { return Promise.reject(Error('the payload is missing a vp_token')) } @@ -83,9 +86,6 @@ export const verifyPresentations = async ( idPayload = await authorizationResponse.idToken.payload() } - // todo: Probably wise to check against request for the location of the submission_data - const presentationSubmission = idPayload?._vp_token?.presentation_submission ?? authorizationResponse.payload.presentation_submission - let wrappedPresentations: WrappedVerifiablePresentation[] = [] const presentationDefinitions = verifyOpts.presentationDefinitions ? Array.isArray(verifyOpts.presentationDefinitions) @@ -93,18 +93,19 @@ export const verifyPresentations = async ( : [verifyOpts.presentationDefinitions] : [] - const dcqlQuery = verifyOpts.dcqlQuery ?? authorizationResponse.authorizationRequest.payload.dcql_query - if (dcqlQuery) { - const dcqlQueryVpToken = DcqlQueryVpToken.parse(JSON.parse(authorizationResponse.payload.vp_token as string)) + let presentationSubmission: PresentationSubmission | undefined - const parsedQuery = DcqlQuery.parse(dcqlQuery) - DcqlQuery.validate(parsedQuery) + let dcqlQuery = verifyOpts.dcqlQuery ?? authorizationResponse?.authorizationRequest?.payload.dcql_query + if (dcqlQuery) { + dcqlQuery = DcqlQuery.parse(dcqlQuery) + DcqlQuery.validate(dcqlQuery) - const presentations = Object.values(dcqlQueryVpToken) as Array - wrappedPresentations = presentations.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: verifyOpts.hasher })) + wrappedPresentations = extractPresentationsFromDcqlVpToken(authorizationResponse.payload.vp_token as string, { hasher: verifyOpts.hasher }) const verifiedPresentations = await Promise.all( - presentations.map((presentation) => verifyOpts.verification.presentationVerificationCallback(presentation, presentationSubmission)), + wrappedPresentations.map((presentation) => + verifyOpts.verification.presentationVerificationCallback(presentation.original as W3CVerifiablePresentation), + ), ) // TODO: assert the submission against the definition @@ -118,9 +119,14 @@ export const verifyPresentations = async ( throw Error(`Failed to verify presentations. ${message}`) } } else { - const presentations = await extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) + const presentations = authorizationResponse.payload.vp_token + ? await extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) + : [] wrappedPresentations = Array.isArray(presentations) ? presentations : [presentations] + // todo: Probably wise to check against request for the location of the submission_data + presentationSubmission = idPayload?._vp_token?.presentation_submission ?? authorizationResponse.payload.presentation_submission + await assertValidVerifiablePresentations({ presentationDefinitions, presentations, @@ -134,12 +140,6 @@ export const verifyPresentations = async ( }) } - // If there are no presentations, and the `assertValidVerifiablePresentations` did not fail - // it means there's no oid4vp response and also not requested - if (wrappedPresentations.length === 0) { - return null - } - const presentationsWithoutMdoc = wrappedPresentations.filter((p) => p.format !== 'mso_mdoc') const nonces = new Set(presentationsWithoutMdoc.map(extractNonceFromWrappedVerifiablePresentation)) if (presentationsWithoutMdoc.length > 0 && nonces.size !== 1) { @@ -163,13 +163,25 @@ export const verifyPresentations = async ( await verifyRevocation(vp, verifyOpts.verification.revocationOpts.revocationVerificationCallback, revocationVerification) } } - return { nonce, presentations: wrappedPresentations, presentationDefinitions, submissionData: presentationSubmission } + if (presentationDefinitions) { + return { nonce, presentations: wrappedPresentations, presentationDefinitions, submissionData: presentationSubmission } + } else { + return { nonce, presentations: wrappedPresentations, dcqlQuery } + } +} + +export const extractPresentationsFromDcqlVpToken = ( + vpToken: DcqlVpToken.Input | string, + opts?: { hasher?: Hasher }, +): WrappedVerifiablePresentation[] => { + const presentations = Object.values(DcqlVpToken.parse(vpToken)) as Array + return presentations.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: opts.hasher })) } -export const extractPresentationsFromVpToken = async ( +export const extractPresentationsFromVpToken = ( vpToken: Array | W3CVerifiablePresentation | CompactSdJwtVc | string, opts?: { hasher?: Hasher }, -): Promise => { +): WrappedVerifiablePresentation[] | WrappedVerifiablePresentation => { const tokens = Array.isArray(vpToken) ? vpToken : [vpToken] const wrappedTokens = tokens.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: opts?.hasher })) diff --git a/packages/siop-oid4vp/lib/authorization-response/Payload.ts b/packages/siop-oid4vp/lib/authorization-response/Payload.ts index bdd7cc80..286c3705 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Payload.ts @@ -28,7 +28,11 @@ export const createResponsePayload = async ( } // vp tokens - await putPresentationSubmissionInLocation(authorizationRequest, responsePayload, responseOpts, idTokenPayload) + if (responseOpts.dcqlQuery) { + responsePayload.vp_token = JSON.stringify(responseOpts.dcqlQuery.credentialQueryIdToPresentation) + } else { + await putPresentationSubmissionInLocation(authorizationRequest, responsePayload, responseOpts, idTokenPayload) + } if (idTokenPayload) { const idToken = await IDToken.fromIDTokenPayload(idTokenPayload, responseOpts) responsePayload.id_token = await idToken.jwt(responseOpts.jwtIssuer) diff --git a/packages/siop-oid4vp/lib/authorization-response/types.ts b/packages/siop-oid4vp/lib/authorization-response/types.ts index 9a6e1bf2..944e0296 100644 --- a/packages/siop-oid4vp/lib/authorization-response/types.ts +++ b/packages/siop-oid4vp/lib/authorization-response/types.ts @@ -9,7 +9,7 @@ import { PresentationSubmission, W3CVerifiablePresentation, } from '@sphereon/ssi-types' -import { DcqlQuery, DcqlQueryVpToken } from 'dcql' +import { DcqlQuery } from 'dcql' import { ResponseMode, @@ -62,7 +62,7 @@ export interface PresentationExchangeResponseOpts { } export interface DcqlQueryResponseOpts { - credentialQueryIdToPresentation: DcqlQueryVpToken + credentialQueryIdToPresentation: Record | string> } export interface PresentationExchangeRequestOpts { @@ -108,7 +108,7 @@ export type PresentationVerificationResult = { verified: boolean; reason?: strin export type PresentationVerificationCallback = ( args: W3CVerifiablePresentation | CompactSdJwtVc | MdocOid4vpIssuerSigned, - presentationSubmission: PresentationSubmission, + presentationSubmission?: PresentationSubmission, ) => Promise export type PresentationSignCallback = (args: PresentationSignCallBackParams) => Promise diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index addc9a23..827db4c4 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -22,6 +22,7 @@ import { import { mergeVerificationOpts } from '../authorization-request/Opts' import { AuthorizationResponse, + extractPresentationsFromDcqlVpToken, extractPresentationsFromVpToken, PresentationDefinitionWithLocation, VerifyAuthorizationResponseOpts, @@ -169,7 +170,10 @@ export class RP { }, ) - const presentations = await extractPresentationsFromVpToken(validatedResponse.authResponseParams.vp_token, { hasher }) + const presentations = validatedResponse.authRequestParams.dcql_query + ? extractPresentationsFromDcqlVpToken(validatedResponse.authResponseParams.vp_token as string, { hasher }) + : extractPresentationsFromVpToken(validatedResponse.authResponseParams.vp_token, { hasher }) + const mdocVerifiablePresentations = (Array.isArray(presentations) ? presentations : [presentations]).filter((p) => p.format === 'mso_mdoc') if (mdocVerifiablePresentations.length) { diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts index 42961fb7..e740951a 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts @@ -122,6 +122,9 @@ export const AuthorizationRequestPayloadVD12OID4VPD20SchemaObj = { }, "response_uri": { "type": "string" + }, + "dcql_query": { + "type": "string" } } }, diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts index 0b78c774..59cc00bf 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts @@ -414,6 +414,9 @@ export const AuthorizationRequestPayloadVID1SchemaObj = { }, "presentation_definition_uri": { "type": "string" + }, + "dcql_query": { + "type": "string" } }, "additionalProperties": false diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts index ffb4eee2..f4665713 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts @@ -52,6 +52,9 @@ export const AuthorizationResponseOptsSchemaObj = { }, "presentationExchange": { "$ref": "#/definitions/PresentationExchangeResponseOpts" + }, + "dcqlQuery": { + "$ref": "#/definitions/DcqlQueryResponseOpts" } }, "required": [ @@ -2335,6 +2338,29 @@ export const AuthorizationResponseOptsSchemaObj = { "id_token", "token_response" ] + }, + "DcqlQueryResponseOpts": { + "type": "object", + "properties": { + "credentialQueryIdToPresentation": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "object", + "additionalProperties": {} + }, + { + "type": "string" + } + ] + } + } + }, + "required": [ + "credentialQueryIdToPresentation" + ], + "additionalProperties": false } } }; \ No newline at end of file diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index 30619c0f..3933216e 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -516,6 +516,12 @@ export interface VerifiedIDToken { verifyOpts: VerifyAuthorizationResponseOpts } +export interface VerifiedOpenID4VPSubmissionDcql { + dcqlQuery: DcqlQuery + presentations: WrappedVerifiablePresentation[] + nonce?: string +} + export interface VerifiedOpenID4VPSubmission { submissionData: PresentationSubmission presentationDefinitions: PresentationDefinitionWithLocation[] @@ -529,6 +535,7 @@ export interface VerifiedAuthorizationResponse { authorizationResponse: AuthorizationResponse oid4vpSubmission?: VerifiedOpenID4VPSubmission + oid4vpSubmissionDcql?: VerifiedOpenID4VPSubmissionDcql nonce?: string state: string From 6ff33553305bf59f7a55259ab7d63ae5398c37fa Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Thu, 21 Nov 2024 09:09:09 +0100 Subject: [PATCH 03/48] fix: dcql alpha --- .../__tests__/PresentationExchange.spec.ts | 4 +-- .../AuthorizationResponse.ts | 23 ++++++++++-- .../lib/authorization-response/Dcql.ts | 33 +++++++++++------ .../lib/authorization-response/OpenID4VP.ts | 35 ++++++++++--------- .../lib/authorization-response/Payload.ts | 4 ++- .../lib/authorization-response/types.ts | 6 +--- .../AuthorizationResponseOpts.schema.ts | 4 +-- packages/siop-oid4vp/lib/types/SIOP.types.ts | 4 +-- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 25 +++++++++++-- 10 files changed, 95 insertions(+), 45 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/PresentationExchange.spec.ts b/packages/siop-oid4vp/lib/__tests__/PresentationExchange.spec.ts index 8d69fd5b..5f907d40 100644 --- a/packages/siop-oid4vp/lib/__tests__/PresentationExchange.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/PresentationExchange.spec.ts @@ -337,9 +337,7 @@ describe('presentation exchange manager tests', () => { const payload = await getPayloadVID1Val() // eslint-disable-next-line @typescript-eslint/no-explicit-any ;(payload.claims?.vp_token as any).presentation_definition_uri = EXAMPLE_PD_URL - await expect(PresentationExchange.findValidPresentationDefinitions(payload)).rejects.toThrow( - SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_BY_REF_AND_VALUE_NON_EXCLUSIVE, - ) + await expect(PresentationExchange.findValidPresentationDefinitions(payload)).rejects.toThrow(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) }) it('validatePresentationAgainstDefinition: should pass if provided VP match the PD', async function () { diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index df4d1288..8e64938f 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -1,10 +1,12 @@ import { CredentialMapper, Hasher, WrappedVerifiablePresentation } from '@sphereon/ssi-types' +import { DcqlPresentationRecord } from 'dcql' import { AuthorizationRequest, VerifyAuthorizationRequestOpts } from '../authorization-request' import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-request/Opts' import { IDToken } from '../id-token' import { AuthorizationResponsePayload, ResponseType, SIOPErrors, VerifiedAuthorizationRequest, VerifiedAuthorizationResponse } from '../types' +import { assertValidDcqlPresentationRecrod } from './Dcql' import { assertValidVerifiablePresentations, extractNonceFromWrappedVerifiablePresentation, @@ -142,7 +144,13 @@ export class AuthorizationResponse { }, }) } else { - console.error('TODO: VALIDATE PRESENTATION AGAINST DEFINITION') + const dcqlQuery = verifiedAuthorizationRequest.dcqlQuery + if (!dcqlQuery) { + throw new Error('vp_token is present, but no presentation definitions or dcql query provided') + } + assertValidDcqlPresentationRecrod(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord, dcqlQuery, { + hasher: verifyOpts.hasher, + }) } } @@ -160,7 +168,16 @@ export class AuthorizationResponse { } const verifiedIdToken = await this.idToken?.verify(verifyOpts) - const oid4vp = await verifyPresentations(this, verifyOpts) + if (this.payload.vp_token && !verifyOpts.presentationDefinitions && !verifyOpts.dcqlQuery) { + throw Promise.reject(Error('vp_token is present, but no presentation definitions or dcql query provided')) + } + + const emptyPresentationDefinitions = Array.isArray(verifyOpts.presentationDefinitions) && verifyOpts.presentationDefinitions.length === 0 + if (!this.payload.vp_token && ((verifyOpts.presentationDefinitions && !emptyPresentationDefinitions) || verifyOpts.dcqlQuery)) { + throw Promise.reject(Error('Presentation definitions or dcql query provided, but no vp_token present')) + } + + const oid4vp = this.payload.vp_token ? await verifyPresentations(this, verifyOpts) : undefined // Gather all nonces const allNonces = new Set() @@ -227,7 +244,7 @@ export class AuthorizationResponse { presentations = extractPresentationsFromVpToken(this._payload.vp_token, opts) } - if (presentations && Array.isArray(presentations) && presentations.length === 0) { + if (!presentations || (Array.isArray(presentations) && presentations.length === 0)) { return Promise.reject(Error('missing presentation(s)')) } const presentationsArray = Array.isArray(presentations) ? presentations : [presentations] diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index 16cf9672..b2488e2e 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -1,8 +1,11 @@ -import { DcqlQuery } from 'dcql' +import { Hasher } from '@sphereon/ssi-types' +import { DcqlMdocRepresentation, DcqlPresentationRecord, DcqlQuery, DcqlSdJwtVcRepresentation } from 'dcql' import { extractDataFromPath } from '../helpers' import { AuthorizationRequestPayload, SIOPErrors } from '../types' +import { extractPresentationRecordFromDcqlVpToken } from './OpenID4VP' + /** * Finds a valid DcqlQuery inside the given AuthenticationRequestPayload * throws exception if the DcqlQuery is not valid @@ -12,7 +15,6 @@ import { AuthorizationRequestPayload, SIOPErrors } from '../types' */ export const findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise => { const dcqlQuery: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query').map((d) => d.value) - const dcqlQueryList: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query[*]').map((d) => d.value) const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition') const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]') const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri') @@ -20,21 +22,32 @@ export const findValidDcqlQuery = async (authorizationRequestPayload: Authorizat const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) - const hasDcql = (dcqlQuery && dcqlQuery.length > 0) || (dcqlQueryList && dcqlQueryList.length > 0) + const hasDcql = dcqlQuery && dcqlQuery.length > 0 if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) { throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) } - if (dcqlQuery.length > 1 || dcqlQueryList.length > 1) { + if (dcqlQuery.length === 0) return undefined + + if (dcqlQuery.length > 1) { throw new Error('Found multiple dcql_query in vp_token. Only one is allowed') } - const encoded = dcqlQuery.length ? dcqlQuery[0] : dcqlQueryList[0] - if (!encoded) return undefined - - const parsedDcqlQuery = DcqlQuery.parse(JSON.parse(encoded)) - DcqlQuery.validate(parsedDcqlQuery) + return DcqlQuery.parse(JSON.parse(dcqlQuery[0])) +} - return parsedDcqlQuery +export const assertValidDcqlPresentationRecrod = async (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { + const wrappedPresentations = Object.values(extractPresentationRecordFromDcqlVpToken(record, opts)) + const credentials = wrappedPresentations.map((p) => { + if (p.format === 'mso_mdoc') { + return { docType: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocRepresentation + } else if (p.format === 'vc+sd-jwt') { + return { vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcRepresentation + } else { + throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') + } + }) + + DcqlPresentationRecord.validate(credentials, { dcqlQuery }) } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 4ff909cf..d1a4e72e 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -10,7 +10,7 @@ import { W3CVerifiablePresentation, WrappedVerifiablePresentation, } from '@sphereon/ssi-types' -import { DcqlQuery, DcqlVpToken } from 'dcql' +import { DcqlPresentationRecord, DcqlQuery } from 'dcql' import { AuthorizationRequest } from '../authorization-request' import { verifyRevocation } from '../helpers' @@ -26,6 +26,7 @@ import { } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' +import { assertValidDcqlPresentationRecrod } from './Dcql' import { PresentationExchange } from './PresentationExchange' import { AuthorizationResponseOpts, @@ -72,15 +73,6 @@ export const verifyPresentations = async ( authorizationResponse: AuthorizationResponse, verifyOpts: VerifyAuthorizationResponseOpts, ): Promise => { - if (!authorizationResponse.payload.vp_token) return null - if ( - authorizationResponse.payload.vp_token && - Array.isArray(authorizationResponse.payload.vp_token) && - authorizationResponse.payload.vp_token.length === 0 - ) { - return Promise.reject(Error('the payload is missing a vp_token')) - } - let idPayload: IDTokenPayload | undefined if (authorizationResponse.idToken) { idPayload = await authorizationResponse.idToken.payload() @@ -98,8 +90,6 @@ export const verifyPresentations = async ( let dcqlQuery = verifyOpts.dcqlQuery ?? authorizationResponse?.authorizationRequest?.payload.dcql_query if (dcqlQuery) { dcqlQuery = DcqlQuery.parse(dcqlQuery) - DcqlQuery.validate(dcqlQuery) - wrappedPresentations = extractPresentationsFromDcqlVpToken(authorizationResponse.payload.vp_token as string, { hasher: verifyOpts.hasher }) const verifiedPresentations = await Promise.all( @@ -108,7 +98,7 @@ export const verifyPresentations = async ( ), ) - // TODO: assert the submission against the definition + assertValidDcqlPresentationRecrod(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) if (verifiedPresentations.some((verified) => !verified)) { const message = verifiedPresentations @@ -170,12 +160,25 @@ export const verifyPresentations = async ( } } +export const extractPresentationRecordFromDcqlVpToken = ( + vpToken: DcqlPresentationRecord.Input | string, + opts?: { hasher?: Hasher }, +): Record => { + const presentationRecord = Object.fromEntries( + Object.entries(DcqlPresentationRecord.parse(vpToken)).map(([credentialQueryId, vp]) => [ + credentialQueryId, + CredentialMapper.toWrappedVerifiablePresentation(vp as W3CVerifiablePresentation | CompactSdJwtVc | string, { hasher: opts.hasher }), + ]), + ) + + return presentationRecord +} + export const extractPresentationsFromDcqlVpToken = ( - vpToken: DcqlVpToken.Input | string, + vpToken: DcqlPresentationRecord.Input | string, opts?: { hasher?: Hasher }, ): WrappedVerifiablePresentation[] => { - const presentations = Object.values(DcqlVpToken.parse(vpToken)) as Array - return presentations.map((vp) => CredentialMapper.toWrappedVerifiablePresentation(vp, { hasher: opts.hasher })) + return Object.values(extractPresentationRecordFromDcqlVpToken(vpToken, opts)) } export const extractPresentationsFromVpToken = ( diff --git a/packages/siop-oid4vp/lib/authorization-response/Payload.ts b/packages/siop-oid4vp/lib/authorization-response/Payload.ts index 286c3705..3016f1b9 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Payload.ts @@ -1,3 +1,5 @@ +import { DcqlPresentationRecord } from 'dcql' + import { AuthorizationRequest } from '../authorization-request' import { IDToken } from '../id-token' import { RequestObject } from '../request-object' @@ -29,7 +31,7 @@ export const createResponsePayload = async ( // vp tokens if (responseOpts.dcqlQuery) { - responsePayload.vp_token = JSON.stringify(responseOpts.dcqlQuery.credentialQueryIdToPresentation) + responsePayload.vp_token = DcqlPresentationRecord.encode(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord) } else { await putPresentationSubmissionInLocation(authorizationRequest, responsePayload, responseOpts, idTokenPayload) } diff --git a/packages/siop-oid4vp/lib/authorization-response/types.ts b/packages/siop-oid4vp/lib/authorization-response/types.ts index 944e0296..aa684320 100644 --- a/packages/siop-oid4vp/lib/authorization-response/types.ts +++ b/packages/siop-oid4vp/lib/authorization-response/types.ts @@ -62,11 +62,7 @@ export interface PresentationExchangeResponseOpts { } export interface DcqlQueryResponseOpts { - credentialQueryIdToPresentation: Record | string> -} - -export interface PresentationExchangeRequestOpts { - presentationVerificationCallback?: PresentationVerificationCallback + encodedPresentationRecord: Record | string> } export interface PresentationDefinitionPayloadOpts { diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts index f4665713..6f3b54f8 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts @@ -2342,7 +2342,7 @@ export const AuthorizationResponseOptsSchemaObj = { "DcqlQueryResponseOpts": { "type": "object", "properties": { - "credentialQueryIdToPresentation": { + "encodedPresentationRecord": { "type": "object", "additionalProperties": { "anyOf": [ @@ -2358,7 +2358,7 @@ export const AuthorizationResponseOptsSchemaObj = { } }, "required": [ - "credentialQueryIdToPresentation" + "encodedPresentationRecord" ], "additionalProperties": false } diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index 3933216e..abb6bcab 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -167,7 +167,7 @@ export interface IDTokenPayload extends JWTPayload { } } -export type DcqlQueryVpToken = string +export type EcodedDcqlQueryVpToken = string export interface AuthorizationResponsePayload { access_token?: string @@ -181,7 +181,7 @@ export interface AuthorizationResponsePayload { | W3CVerifiablePresentation | CompactSdJwtVc | MdocOid4vpMdocVpToken - | DcqlQueryVpToken + | EcodedDcqlQueryVpToken presentation_submission?: PresentationSubmission verifiedData?: IPresentation | AdditionalClaims // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index ad8ea863..213f2c2d 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "link:../../../dcql/dcql", + "dcql": "^0.2.7", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.129", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b16db23d..c5b50416 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: link:../../../dcql/dcql - version: link:../../../dcql/dcql + specifier: ^0.2.7 + version: 0.2.7(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -4079,6 +4079,9 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dcql@0.2.7: + resolution: {integrity: sha512-Aap1BFjFDHYmtwDWk4v/lhpfZXfnNeQ4WDSIR4pU48kb5FQjnwXkI0csr2Vij8F1nxn0SHWdDiq5iIasJeUDBQ==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -8506,6 +8509,14 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + valibot@0.37.0: + resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + valibot@0.42.1: resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: @@ -14455,6 +14466,12 @@ snapshots: dayjs@1.11.13: {} + dcql@0.2.7(typescript@5.4.5): + dependencies: + valibot: 0.37.0(typescript@5.4.5) + transitivePeerDependencies: + - typescript + debug@2.6.9: dependencies: ms: 2.0.0 @@ -20076,6 +20093,10 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + valibot@0.37.0(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + valibot@0.42.1(typescript@5.5.3): optionalDependencies: typescript: 5.5.3 From 6ad4d89e6ad97b4d4d1155722e71477e36decc59 Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Thu, 21 Nov 2024 14:12:14 +0100 Subject: [PATCH 04/48] feat: add things --- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 213f2c2d..007e4490 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.7", + "dcql": "^0.2.8", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.129", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5b50416..258681de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.7 - version: 0.2.7(typescript@5.4.5) + specifier: ^0.2.8 + version: 0.2.8(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -4079,8 +4079,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.7: - resolution: {integrity: sha512-Aap1BFjFDHYmtwDWk4v/lhpfZXfnNeQ4WDSIR4pU48kb5FQjnwXkI0csr2Vij8F1nxn0SHWdDiq5iIasJeUDBQ==} + dcql@0.2.8: + resolution: {integrity: sha512-/2TbRz3Itj/as4JnmzkupNxq6slN/w07EEx9iAwb/LRI8M8ajhnSN7YQ8rFopImuZAZkPYzOs4zga7zH6xf8eg==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -14466,7 +14466,7 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.7(typescript@5.4.5): + dcql@0.2.8(typescript@5.4.5): dependencies: valibot: 0.37.0(typescript@5.4.5) transitivePeerDependencies: From 6d94367ad7c64a6ca4e170b54cd83e7e490b8d6b Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Thu, 21 Nov 2024 17:52:24 +0100 Subject: [PATCH 05/48] feat: update dcql lib --- package.json | 3 +- .../AuthorizationResponse.ts | 4 +- .../lib/authorization-response/Dcql.ts | 10 +++- .../lib/authorization-response/OpenID4VP.ts | 4 +- .../lib/authorization-response/index.ts | 1 + packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 49 ++++++++----------- 7 files changed, 36 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index ac994988..7d119b6c 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,5 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ], - "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" + ] } diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 8e64938f..0e2c8112 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -6,7 +6,7 @@ import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-requ import { IDToken } from '../id-token' import { AuthorizationResponsePayload, ResponseType, SIOPErrors, VerifiedAuthorizationRequest, VerifiedAuthorizationResponse } from '../types' -import { assertValidDcqlPresentationRecrod } from './Dcql' +import { assertValidDcqlPresentationRecord } from './Dcql' import { assertValidVerifiablePresentations, extractNonceFromWrappedVerifiablePresentation, @@ -148,7 +148,7 @@ export class AuthorizationResponse { if (!dcqlQuery) { throw new Error('vp_token is present, but no presentation definitions or dcql query provided') } - assertValidDcqlPresentationRecrod(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord, dcqlQuery, { + assertValidDcqlPresentationRecord(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord, dcqlQuery, { hasher: verifyOpts.hasher, }) } diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index b2488e2e..86bd5e83 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -1,5 +1,6 @@ import { Hasher } from '@sphereon/ssi-types' import { DcqlMdocRepresentation, DcqlPresentationRecord, DcqlQuery, DcqlSdJwtVcRepresentation } from 'dcql' +import { DcqlPresentationQueryResult } from 'dcql' import { extractDataFromPath } from '../helpers' import { AuthorizationRequestPayload, SIOPErrors } from '../types' @@ -37,7 +38,7 @@ export const findValidDcqlQuery = async (authorizationRequestPayload: Authorizat return DcqlQuery.parse(JSON.parse(dcqlQuery[0])) } -export const assertValidDcqlPresentationRecrod = async (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { +export const getDcqlPresentationResult = (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { const wrappedPresentations = Object.values(extractPresentationRecordFromDcqlVpToken(record, opts)) const credentials = wrappedPresentations.map((p) => { if (p.format === 'mso_mdoc') { @@ -49,5 +50,10 @@ export const assertValidDcqlPresentationRecrod = async (record: DcqlPresentation } }) - DcqlPresentationRecord.validate(credentials, { dcqlQuery }) + return DcqlPresentationQueryResult.query(credentials, { dcqlQuery }) +} + +export const assertValidDcqlPresentationRecord = async (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { + const result = getDcqlPresentationResult(record, dcqlQuery, opts) + return DcqlPresentationQueryResult.validate(result) } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index d1a4e72e..7de528a8 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -26,7 +26,7 @@ import { } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' -import { assertValidDcqlPresentationRecrod } from './Dcql' +import { assertValidDcqlPresentationRecord } from './Dcql' import { PresentationExchange } from './PresentationExchange' import { AuthorizationResponseOpts, @@ -98,7 +98,7 @@ export const verifyPresentations = async ( ), ) - assertValidDcqlPresentationRecrod(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) + assertValidDcqlPresentationRecord(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) if (verifiedPresentations.some((verified) => !verified)) { const message = verifiedPresentations diff --git a/packages/siop-oid4vp/lib/authorization-response/index.ts b/packages/siop-oid4vp/lib/authorization-response/index.ts index c8ae3c97..5fff5253 100644 --- a/packages/siop-oid4vp/lib/authorization-response/index.ts +++ b/packages/siop-oid4vp/lib/authorization-response/index.ts @@ -3,3 +3,4 @@ export * from './types' export * from './Payload' export * from './ResponseRegistration' export * from './OpenID4VP' +export * from './Dcql' diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 007e4490..ba6634e1 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.8", + "dcql": "^0.2.11", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.129", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 258681de..d62e60f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.8 - version: 0.2.8(typescript@5.4.5) + specifier: ^0.2.11 + version: 0.2.11(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -1867,7 +1867,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.7.3': resolution: {integrity: sha512-uMGHbAhApqXR2sd1KPhgvpbOhBBnspad8msEqHleT2PHXwKIwTUDzBGO9+jdOAWwCx2MJfw3+asYjzoD3DN9Bg==} @@ -2547,7 +2547,6 @@ packages: '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22': resolution: {integrity: sha512-uAZZExVy+ug9JLircejWa5eLtAZ7bnBP6xb7DO2+86LRsHNLh2k2jMWJYxp+iWtGHTsh6RYsZl14ScQLvjiQ/A==} - bundledDependencies: [] '@sphereon/pex-models@2.3.1': resolution: {integrity: sha512-SByU4cJ0XYA6VZQ/L6lsSiRcFtBPHbFioCeQ4GP7/W/jQ+PSBD7uK2oTnKQ9/0iEiMK/6JYqhKgLs4a9UX3UTQ==} @@ -3052,6 +3051,7 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} + deprecated: this version is no longer supported, please update to at least 0.8.* '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} @@ -3477,6 +3477,7 @@ packages: boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -4079,8 +4080,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.8: - resolution: {integrity: sha512-/2TbRz3Itj/as4JnmzkupNxq6slN/w07EEx9iAwb/LRI8M8ajhnSN7YQ8rFopImuZAZkPYzOs4zga7zH6xf8eg==} + dcql@0.2.11: + resolution: {integrity: sha512-hR8MuSx49b7JPoZztcFMSKEHc6iEE4l/Zs6aUsvMCWVa3qFWpuJRiJEp5Rh2+UkCAhsce94fbDpMdBTcS9zn7g==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -4238,10 +4239,6 @@ packages: did-context@3.1.1: resolution: {integrity: sha512-iFpszgSxc7d1kNBJWC+PAzNTpe5LPalzsIunTMIpbG3O37Q7Zi7u4iIaedaM7UhziBhT+Agr9DyvAiXSUyfepQ==} - did-jwt-vc@3.1.3: - resolution: {integrity: sha512-qB1FiQ0sT/FUR5+mQ//P5lS0Gllrtes2OxC3WVMOt8ND0LolF92ohozv50ukyOvB2zBzgfm5durcIPqQcoI+LA==} - engines: {node: '>=14'} - did-jwt-vc@3.2.15: resolution: {integrity: sha512-M/WPiL34CQUiN4bvWnZ0OFHJ3usPtstfQfbNbHAWHvwjeCGi7nAdv62VXHgy2xIhJMc790hH7PsMN3i6SCGEyg==} engines: {node: '>=18'} @@ -4518,6 +4515,7 @@ packages: eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -10795,7 +10793,7 @@ snapshots: '@expo/bunyan': 4.0.0 '@expo/metro-config': 0.7.1 '@expo/osascript': 2.0.33 - '@expo/spawn-async': 1.5.0 + '@expo/spawn-async': 1.7.2 body-parser: 1.20.3 chalk: 4.1.2 connect: 3.7.0 @@ -10871,7 +10869,7 @@ snapshots: '@expo/osascript@2.0.33': dependencies: - '@expo/spawn-async': 1.5.0 + '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 '@expo/osascript@2.1.3': @@ -10882,7 +10880,7 @@ snapshots: '@expo/package-manager@1.0.3': dependencies: '@expo/json-file': 8.3.3 - '@expo/spawn-async': 1.5.0 + '@expo/spawn-async': 1.7.2 ansi-regex: 5.0.1 chalk: 4.1.2 find-up: 5.0.0 @@ -13199,7 +13197,7 @@ snapshots: cross-fetch: 3.1.8(encoding@0.1.13) debug: 4.3.7 did-jwt: 6.11.6 - did-jwt-vc: 3.1.3 + did-jwt-vc: 3.2.15 did-resolver: 4.1.0 elliptic: 6.5.7 multiformats: 9.7.1 @@ -14466,7 +14464,7 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.8(typescript@5.4.5): + dcql@0.2.11(typescript@5.4.5): dependencies: valibot: 0.37.0(typescript@5.4.5) transitivePeerDependencies: @@ -14600,11 +14598,6 @@ snapshots: did-context@3.1.1: {} - did-jwt-vc@3.1.3: - dependencies: - did-jwt: 6.11.6 - did-resolver: 4.1.0 - did-jwt-vc@3.2.15: dependencies: did-jwt: 7.4.7 @@ -15125,9 +15118,9 @@ snapshots: execa@5.0.0: dependencies: cross-spawn: 7.0.3 - get-stream: 6.0.0 + get-stream: 6.0.1 human-signals: 2.1.0 - is-stream: 2.0.0 + is-stream: 2.0.1 merge-stream: 2.0.0 npm-run-path: 4.0.1 onetime: 5.1.2 @@ -16468,7 +16461,7 @@ snapshots: jest-diff@29.7.0: dependencies: - chalk: 4.1.0 + chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 @@ -17253,7 +17246,7 @@ snapshots: log-symbols@4.1.0: dependencies: - chalk: 4.1.0 + chalk: 4.1.2 is-unicode-supported: 0.1.0 logkitty@0.7.1: @@ -17885,7 +17878,7 @@ snapshots: array-differ: 3.0.0 array-union: 2.1.0 arrify: 2.0.1 - minimatch: 3.0.5 + minimatch: 3.1.2 mute-stream@0.0.8: {} @@ -18116,7 +18109,7 @@ snapshots: '@yarnpkg/parsers': 3.0.0-rc.46 '@zkochan/js-yaml': 0.0.7 axios: 1.7.7(debug@4.3.7) - chalk: 4.1.0 + chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 @@ -18299,9 +18292,9 @@ snapshots: ora@5.3.0: dependencies: bl: 4.1.0 - chalk: 4.1.0 + chalk: 4.1.2 cli-cursor: 3.1.0 - cli-spinners: 2.6.1 + cli-spinners: 2.9.2 is-interactive: 1.0.0 log-symbols: 4.1.0 strip-ansi: 6.0.1 From 413ecb9af2fa4010ef177272d320045f6148747f Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Fri, 22 Nov 2024 19:58:53 +0100 Subject: [PATCH 06/48] fix: feedback --- package.json | 3 +- .../AuthorizationRequest.ts | 2 +- .../AuthorizationResponse.ts | 56 +++++++++---------- .../lib/authorization-response/Dcql.ts | 36 ++++++------ .../lib/authorization-response/OpenID4VP.ts | 33 ++++++----- .../lib/authorization-response/Payload.ts | 4 +- .../lib/authorization-response/types.ts | 2 +- .../AuthorizationResponseOpts.schema.ts | 4 +- packages/siop-oid4vp/lib/types/Errors.ts | 2 +- packages/siop-oid4vp/lib/types/SIOP.types.ts | 6 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 13 +++-- 12 files changed, 84 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index 7d119b6c..ac994988 100644 --- a/package.json +++ b/package.json @@ -63,5 +63,6 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ] + ], + "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" } diff --git a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts index aeb4b15b..c3bfd6ed 100644 --- a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts +++ b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts @@ -290,7 +290,7 @@ export class AuthorizationRequest { return await PresentationExchange.findValidPresentationDefinitions(await this.mergedPayloads(), version) } - public async getDcqlQuery(): Promise { + public async getDcqlQuery(): Promise { return await findValidDcqlQuery(await this.mergedPayloads()) } } diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 0e2c8112..26fa302c 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -1,12 +1,12 @@ import { CredentialMapper, Hasher, WrappedVerifiablePresentation } from '@sphereon/ssi-types' -import { DcqlPresentationRecord } from 'dcql' +import { DcqlPresentation } from 'dcql' import { AuthorizationRequest, VerifyAuthorizationRequestOpts } from '../authorization-request' import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-request/Opts' import { IDToken } from '../id-token' import { AuthorizationResponsePayload, ResponseType, SIOPErrors, VerifiedAuthorizationRequest, VerifiedAuthorizationResponse } from '../types' -import { assertValidDcqlPresentationRecord } from './Dcql' +import { assertValidDcqlPresentation } from './Dcql' import { assertValidVerifiablePresentations, extractNonceFromWrappedVerifiablePresentation, @@ -126,32 +126,32 @@ export class AuthorizationResponse { authorizationRequest, }) - if (hasVpToken) { - if (responseOpts.presentationExchange) { - const wrappedPresentations = response.payload.vp_token - ? await extractPresentationsFromVpToken(response.payload.vp_token, { - hasher: verifyOpts.hasher, - }) - : [] - - await assertValidVerifiablePresentations({ - presentationDefinitions, - presentations: wrappedPresentations, - verificationCallback: verifyOpts.verification.presentationVerificationCallback, - opts: { - ...responseOpts.presentationExchange, + if (!hasVpToken) return response + + if (responseOpts.presentationExchange) { + const wrappedPresentations = response.payload.vp_token + ? await extractPresentationsFromVpToken(response.payload.vp_token, { hasher: verifyOpts.hasher, - }, - }) - } else { - const dcqlQuery = verifiedAuthorizationRequest.dcqlQuery - if (!dcqlQuery) { - throw new Error('vp_token is present, but no presentation definitions or dcql query provided') - } - assertValidDcqlPresentationRecord(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord, dcqlQuery, { + }) + : [] + + await assertValidVerifiablePresentations({ + presentationDefinitions, + presentations: wrappedPresentations, + verificationCallback: verifyOpts.verification.presentationVerificationCallback, + opts: { + ...responseOpts.presentationExchange, hasher: verifyOpts.hasher, - }) + }, + }) + } else { + const dcqlQuery = verifiedAuthorizationRequest.dcqlQuery + if (!dcqlQuery) { + throw new Error('vp_token is present, but no presentation definitions or dcql query provided') } + assertValidDcqlPresentation(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, dcqlQuery, { + hasher: verifyOpts.hasher, + }) } return response @@ -181,7 +181,7 @@ export class AuthorizationResponse { // Gather all nonces const allNonces = new Set() - if (oid4vp && oid4vp.nonce) allNonces.add(oid4vp.nonce) + if (oid4vp && (oid4vp.dcql.nonce || oid4vp.presentationExchange.nonce)) allNonces.add(oid4vp.dcql.nonce ?? oid4vp.presentationExchange.nonce) if (verifiedIdToken) allNonces.add(verifiedIdToken.payload.nonce) if (merged.nonce) allNonces.add(merged.nonce) @@ -207,8 +207,8 @@ export class AuthorizationResponse { state, correlationId: verifyOpts.correlationId, ...(this.idToken && { idToken: verifiedIdToken }), - ...(oid4vp && 'presentationDefinitions' in oid4vp && { oid4vpSubmission: oid4vp }), - ...(oid4vp && 'dcqlQuery' in oid4vp && { oid4vpSubmissionDcql: oid4vp }), + ...(oid4vp.presentationExchange && { oid4vpSubmission: oid4vp.presentationExchange }), + ...(oid4vp.dcql && { oid4vpSubmissionDcql: oid4vp.dcql }), } } diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index 86bd5e83..71662d91 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -1,11 +1,10 @@ import { Hasher } from '@sphereon/ssi-types' -import { DcqlMdocRepresentation, DcqlPresentationRecord, DcqlQuery, DcqlSdJwtVcRepresentation } from 'dcql' -import { DcqlPresentationQueryResult } from 'dcql' +import { DcqlMdocCredential, DcqlPresentation, DcqlPresentationResult, DcqlQuery, DcqlSdJwtVcCredential } from 'dcql' import { extractDataFromPath } from '../helpers' import { AuthorizationRequestPayload, SIOPErrors } from '../types' -import { extractPresentationRecordFromDcqlVpToken } from './OpenID4VP' +import { extractDcqlPresentationFromDcqlVpToken } from './OpenID4VP' /** * Finds a valid DcqlQuery inside the given AuthenticationRequestPayload @@ -38,22 +37,23 @@ export const findValidDcqlQuery = async (authorizationRequestPayload: Authorizat return DcqlQuery.parse(JSON.parse(dcqlQuery[0])) } -export const getDcqlPresentationResult = (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { - const wrappedPresentations = Object.values(extractPresentationRecordFromDcqlVpToken(record, opts)) - const credentials = wrappedPresentations.map((p) => { - if (p.format === 'mso_mdoc') { - return { docType: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocRepresentation - } else if (p.format === 'vc+sd-jwt') { - return { vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcRepresentation - } else { - throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') - } - }) - - return DcqlPresentationQueryResult.query(credentials, { dcqlQuery }) +export const getDcqlPresentationResult = (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { + const dcqlPresentation = Object.fromEntries( + Object.entries(extractDcqlPresentationFromDcqlVpToken(record, opts)).map(([queryId, p]) => { + if (p.format === 'mso_mdoc') { + return [queryId, { docType: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential] + } else if (p.format === 'vc+sd-jwt') { + return [queryId, { vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] + } else { + throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') + } + }), + ) + + return DcqlPresentationResult.fromDcqlPresentation(dcqlPresentation, { dcqlQuery }) } -export const assertValidDcqlPresentationRecord = async (record: DcqlPresentationRecord | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { +export const assertValidDcqlPresentation = async (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { const result = getDcqlPresentationResult(record, dcqlQuery, opts) - return DcqlPresentationQueryResult.validate(result) + return DcqlPresentationResult.validate(result) } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 7de528a8..3f1c8b30 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -10,7 +10,7 @@ import { W3CVerifiablePresentation, WrappedVerifiablePresentation, } from '@sphereon/ssi-types' -import { DcqlPresentationRecord, DcqlQuery } from 'dcql' +import { DcqlPresentation, DcqlQuery } from 'dcql' import { AuthorizationRequest } from '../authorization-request' import { verifyRevocation } from '../helpers' @@ -26,7 +26,7 @@ import { } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' -import { assertValidDcqlPresentationRecord } from './Dcql' +import { assertValidDcqlPresentation as assertValidDcqlPresentation } from './Dcql' import { PresentationExchange } from './PresentationExchange' import { AuthorizationResponseOpts, @@ -72,7 +72,7 @@ export const extractNonceFromWrappedVerifiablePresentation = (wrappedVp: Wrapped export const verifyPresentations = async ( authorizationResponse: AuthorizationResponse, verifyOpts: VerifyAuthorizationResponseOpts, -): Promise => { +): Promise<{ presentationExchange?: VerifiedOpenID4VPSubmission; dcql?: VerifiedOpenID4VPSubmissionDcql }> => { let idPayload: IDTokenPayload | undefined if (authorizationResponse.idToken) { idPayload = await authorizationResponse.idToken.payload() @@ -87,10 +87,13 @@ export const verifyPresentations = async ( let presentationSubmission: PresentationSubmission | undefined + let dcqlPresentation: { [credentialQueryId: string]: WrappedVerifiablePresentation } | undefined + let dcqlQuery = verifyOpts.dcqlQuery ?? authorizationResponse?.authorizationRequest?.payload.dcql_query if (dcqlQuery) { dcqlQuery = DcqlQuery.parse(dcqlQuery) - wrappedPresentations = extractPresentationsFromDcqlVpToken(authorizationResponse.payload.vp_token as string, { hasher: verifyOpts.hasher }) + dcqlPresentation = extractDcqlPresentationFromDcqlVpToken(authorizationResponse.payload.vp_token as string, { hasher: verifyOpts.hasher }) + wrappedPresentations = Object.values(dcqlPresentation) const verifiedPresentations = await Promise.all( wrappedPresentations.map((presentation) => @@ -98,7 +101,7 @@ export const verifyPresentations = async ( ), ) - assertValidDcqlPresentationRecord(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) + assertValidDcqlPresentation(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) if (verifiedPresentations.some((verified) => !verified)) { const message = verifiedPresentations @@ -154,31 +157,31 @@ export const verifyPresentations = async ( } } if (presentationDefinitions) { - return { nonce, presentations: wrappedPresentations, presentationDefinitions, submissionData: presentationSubmission } + return { presentationExchange: { nonce, presentations: wrappedPresentations, presentationDefinitions, submissionData: presentationSubmission } } } else { - return { nonce, presentations: wrappedPresentations, dcqlQuery } + return { dcql: { nonce, presentation: dcqlPresentation, dcqlQuery } } } } -export const extractPresentationRecordFromDcqlVpToken = ( - vpToken: DcqlPresentationRecord.Input | string, +export const extractDcqlPresentationFromDcqlVpToken = ( + vpToken: DcqlPresentation.Input | string, opts?: { hasher?: Hasher }, -): Record => { - const presentationRecord = Object.fromEntries( - Object.entries(DcqlPresentationRecord.parse(vpToken)).map(([credentialQueryId, vp]) => [ +): { [credentialQueryId: string]: WrappedVerifiablePresentation } => { + const dcqlPresentation = Object.fromEntries( + Object.entries(DcqlPresentation.parse(vpToken)).map(([credentialQueryId, vp]) => [ credentialQueryId, CredentialMapper.toWrappedVerifiablePresentation(vp as W3CVerifiablePresentation | CompactSdJwtVc | string, { hasher: opts.hasher }), ]), ) - return presentationRecord + return dcqlPresentation } export const extractPresentationsFromDcqlVpToken = ( - vpToken: DcqlPresentationRecord.Input | string, + vpToken: DcqlPresentation.Input | string, opts?: { hasher?: Hasher }, ): WrappedVerifiablePresentation[] => { - return Object.values(extractPresentationRecordFromDcqlVpToken(vpToken, opts)) + return Object.values(extractDcqlPresentationFromDcqlVpToken(vpToken, opts)) } export const extractPresentationsFromVpToken = ( diff --git a/packages/siop-oid4vp/lib/authorization-response/Payload.ts b/packages/siop-oid4vp/lib/authorization-response/Payload.ts index 3016f1b9..a2bc60b9 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Payload.ts @@ -1,4 +1,4 @@ -import { DcqlPresentationRecord } from 'dcql' +import { DcqlPresentation } from 'dcql' import { AuthorizationRequest } from '../authorization-request' import { IDToken } from '../id-token' @@ -31,7 +31,7 @@ export const createResponsePayload = async ( // vp tokens if (responseOpts.dcqlQuery) { - responsePayload.vp_token = DcqlPresentationRecord.encode(responseOpts.dcqlQuery.encodedPresentationRecord as DcqlPresentationRecord) + responsePayload.vp_token = DcqlPresentation.encode(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation) } else { await putPresentationSubmissionInLocation(authorizationRequest, responsePayload, responseOpts, idTokenPayload) } diff --git a/packages/siop-oid4vp/lib/authorization-response/types.ts b/packages/siop-oid4vp/lib/authorization-response/types.ts index aa684320..5f8f2b6f 100644 --- a/packages/siop-oid4vp/lib/authorization-response/types.ts +++ b/packages/siop-oid4vp/lib/authorization-response/types.ts @@ -62,7 +62,7 @@ export interface PresentationExchangeResponseOpts { } export interface DcqlQueryResponseOpts { - encodedPresentationRecord: Record | string> + dcqlPresentation: Record | string> } export interface PresentationDefinitionPayloadOpts { diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts index 6f3b54f8..1478d7b7 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts @@ -2342,7 +2342,7 @@ export const AuthorizationResponseOptsSchemaObj = { "DcqlQueryResponseOpts": { "type": "object", "properties": { - "encodedPresentationRecord": { + "dcqlPresentation": { "type": "object", "additionalProperties": { "anyOf": [ @@ -2358,7 +2358,7 @@ export const AuthorizationResponseOptsSchemaObj = { } }, "required": [ - "encodedPresentationRecord" + "dcqlPresentation" ], "additionalProperties": false } diff --git a/packages/siop-oid4vp/lib/types/Errors.ts b/packages/siop-oid4vp/lib/types/Errors.ts index 780d8c17..fa08b9d8 100644 --- a/packages/siop-oid4vp/lib/types/Errors.ts +++ b/packages/siop-oid4vp/lib/types/Errors.ts @@ -38,7 +38,7 @@ enum SIOPErrors { REFERENCE_URI_NO_PAYLOAD = 'referenceUri specified, but object to host there is not present', NO_SELF_ISSUED_ISS = 'The Response Token Issuer Claim (iss) MUST start with https://self-isued.me/v2', REGISTRATION_NOT_SET = 'Registration metadata not set.', - REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE = "Request claims can't multiple of 'presentation_definition' and 'presentation_definition_uri' 'dcql_query", + REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE = "Request claims can't have multiple of 'presentation_definition', 'presentation_definition_uri' and 'dcql_query", REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID = 'Presentation definition in the request claims is not valid', REQUEST_OBJECT_TYPE_NOT_SET = 'Request object type is not set.', RESPONSE_OPTS_PRESENTATIONS_SUBMISSION_IS_NOT_VALID = 'presentation_submission object inside the response opts vp should be valid', diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index abb6bcab..e0b78ff8 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -167,7 +167,7 @@ export interface IDTokenPayload extends JWTPayload { } } -export type EcodedDcqlQueryVpToken = string +export type EncodedDcqlQueryVpToken = string export interface AuthorizationResponsePayload { access_token?: string @@ -181,7 +181,7 @@ export interface AuthorizationResponsePayload { | W3CVerifiablePresentation | CompactSdJwtVc | MdocOid4vpMdocVpToken - | EcodedDcqlQueryVpToken + | EncodedDcqlQueryVpToken presentation_submission?: PresentationSubmission verifiedData?: IPresentation | AdditionalClaims // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -518,7 +518,7 @@ export interface VerifiedIDToken { export interface VerifiedOpenID4VPSubmissionDcql { dcqlQuery: DcqlQuery - presentations: WrappedVerifiablePresentation[] + presentation: { [credentialQueryId: string]: WrappedVerifiablePresentation } nonce?: string } diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index ba6634e1..dd294260 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.11", + "dcql": "^0.2.12", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.129", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d62e60f5..9b647e54 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.11 - version: 0.2.11(typescript@5.4.5) + specifier: ^0.2.12 + version: 0.2.12(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -1867,7 +1867,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + engines: {'0': node >=0.10.0} '@expo/cli@0.7.3': resolution: {integrity: sha512-uMGHbAhApqXR2sd1KPhgvpbOhBBnspad8msEqHleT2PHXwKIwTUDzBGO9+jdOAWwCx2MJfw3+asYjzoD3DN9Bg==} @@ -2547,6 +2547,7 @@ packages: '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22': resolution: {integrity: sha512-uAZZExVy+ug9JLircejWa5eLtAZ7bnBP6xb7DO2+86LRsHNLh2k2jMWJYxp+iWtGHTsh6RYsZl14ScQLvjiQ/A==} + bundledDependencies: [] '@sphereon/pex-models@2.3.1': resolution: {integrity: sha512-SByU4cJ0XYA6VZQ/L6lsSiRcFtBPHbFioCeQ4GP7/W/jQ+PSBD7uK2oTnKQ9/0iEiMK/6JYqhKgLs4a9UX3UTQ==} @@ -4080,8 +4081,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.11: - resolution: {integrity: sha512-hR8MuSx49b7JPoZztcFMSKEHc6iEE4l/Zs6aUsvMCWVa3qFWpuJRiJEp5Rh2+UkCAhsce94fbDpMdBTcS9zn7g==} + dcql@0.2.12: + resolution: {integrity: sha512-Ag2HTeMio8Gz8/K2T+VrT9wx+nxBst4goOeYbD/UXfiRnbH1MuPW1JW8zlmHmWFfzxl7KikaiQtr1ipLwNCYNA==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -14464,7 +14465,7 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.11(typescript@5.4.5): + dcql@0.2.12(typescript@5.4.5): dependencies: valibot: 0.37.0(typescript@5.4.5) transitivePeerDependencies: From 9ff62bd5127a69f33a158fe8f0be21ca9820879a Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Sat, 23 Nov 2024 09:59:56 +0100 Subject: [PATCH 07/48] fix: update --- .../AuthorizationResponse.ts | 10 +++++----- .../siop-oid4vp/lib/authorization-response/Dcql.ts | 9 ++++++--- .../lib/authorization-response/OpenID4VP.ts | 14 +++++++------- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 26fa302c..c1c71212 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -6,7 +6,7 @@ import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-requ import { IDToken } from '../id-token' import { AuthorizationResponsePayload, ResponseType, SIOPErrors, VerifiedAuthorizationRequest, VerifiedAuthorizationResponse } from '../types' -import { assertValidDcqlPresentation } from './Dcql' +import { assertValidDcqlPresentationResult } from './Dcql' import { assertValidVerifiablePresentations, extractNonceFromWrappedVerifiablePresentation, @@ -149,7 +149,7 @@ export class AuthorizationResponse { if (!dcqlQuery) { throw new Error('vp_token is present, but no presentation definitions or dcql query provided') } - assertValidDcqlPresentation(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, dcqlQuery, { + assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, dcqlQuery, { hasher: verifyOpts.hasher, }) } @@ -169,19 +169,19 @@ export class AuthorizationResponse { const verifiedIdToken = await this.idToken?.verify(verifyOpts) if (this.payload.vp_token && !verifyOpts.presentationDefinitions && !verifyOpts.dcqlQuery) { - throw Promise.reject(Error('vp_token is present, but no presentation definitions or dcql query provided')) + throw new Error('vp_token is present, but no presentation definitions or dcql query provided') } const emptyPresentationDefinitions = Array.isArray(verifyOpts.presentationDefinitions) && verifyOpts.presentationDefinitions.length === 0 if (!this.payload.vp_token && ((verifyOpts.presentationDefinitions && !emptyPresentationDefinitions) || verifyOpts.dcqlQuery)) { - throw Promise.reject(Error('Presentation definitions or dcql query provided, but no vp_token present')) + throw new Error('Presentation definitions or dcql query provided, but no vp_token present') } const oid4vp = this.payload.vp_token ? await verifyPresentations(this, verifyOpts) : undefined // Gather all nonces const allNonces = new Set() - if (oid4vp && (oid4vp.dcql.nonce || oid4vp.presentationExchange.nonce)) allNonces.add(oid4vp.dcql.nonce ?? oid4vp.presentationExchange.nonce) + if (oid4vp && (oid4vp.dcql?.nonce || oid4vp.presentationExchange?.nonce)) allNonces.add(oid4vp.dcql?.nonce ?? oid4vp.presentationExchange?.nonce) if (verifiedIdToken) allNonces.add(verifiedIdToken.payload.nonce) if (merged.nonce) allNonces.add(merged.nonce) diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index 71662d91..77ab1da5 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -41,9 +41,12 @@ export const getDcqlPresentationResult = (record: DcqlPresentation | string, dcq const dcqlPresentation = Object.fromEntries( Object.entries(extractDcqlPresentationFromDcqlVpToken(record, opts)).map(([queryId, p]) => { if (p.format === 'mso_mdoc') { - return [queryId, { docType: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential] + return [ + queryId, + { credentialFormat: 'mso_mdoc', doctype: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential, + ] } else if (p.format === 'vc+sd-jwt') { - return [queryId, { vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] + return [queryId, { credentialFormat: 'vc+sd-jwt', vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] } else { throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') } @@ -53,7 +56,7 @@ export const getDcqlPresentationResult = (record: DcqlPresentation | string, dcq return DcqlPresentationResult.fromDcqlPresentation(dcqlPresentation, { dcqlQuery }) } -export const assertValidDcqlPresentation = async (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { +export const assertValidDcqlPresentationResult = async (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { const result = getDcqlPresentationResult(record, dcqlQuery, opts) return DcqlPresentationResult.validate(result) } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 9dc1aeef..d1177ef4 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -26,7 +26,7 @@ import { } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' -import { assertValidDcqlPresentation as assertValidDcqlPresentation } from './Dcql' +import { assertValidDcqlPresentationResult } from './Dcql' import { PresentationExchange } from './PresentationExchange' import { AuthorizationResponseOpts, @@ -101,7 +101,7 @@ export const verifyPresentations = async ( ), ) - assertValidDcqlPresentation(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) + assertValidDcqlPresentationResult(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) if (verifiedPresentations.some((verified) => !verified)) { const message = verifiedPresentations @@ -337,14 +337,14 @@ export const assertValidVerifiablePresentations = async (args: { if (!presentations || (Array.isArray(presentations) && presentations.length === 0)) { return Promise.reject(Error('missing presentation(s)')) } - + // Handle mdocs, keep them out of pex - let presentationsArray = (Array.isArray(presentations) ? presentations : [presentations]) - if (presentationsArray.every(p => p.format === 'mso_mdoc')) { + let presentationsArray = Array.isArray(presentations) ? presentations : [presentations] + if (presentationsArray.every((p) => p.format === 'mso_mdoc')) { return - } + } presentationsArray = presentationsArray.filter((p) => p.format !== 'mso_mdoc') - + if ( (!args.presentationDefinitions || args.presentationDefinitions.filter((a) => a.definition).length === 0) && (!presentationsArray || (Array.isArray(presentationsArray) && presentationsArray.filter((vp) => vp.presentation).length === 0)) diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 52e37a7f..937ce385 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.12", + "dcql": "^0.2.13", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.279", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e89464f..f4e47bc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.12 - version: 0.2.12(typescript@5.4.5) + specifier: ^0.2.13 + version: 0.2.13(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -1867,7 +1867,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.7.3': resolution: {integrity: sha512-uMGHbAhApqXR2sd1KPhgvpbOhBBnspad8msEqHleT2PHXwKIwTUDzBGO9+jdOAWwCx2MJfw3+asYjzoD3DN9Bg==} @@ -4015,8 +4015,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.12: - resolution: {integrity: sha512-Ag2HTeMio8Gz8/K2T+VrT9wx+nxBst4goOeYbD/UXfiRnbH1MuPW1JW8zlmHmWFfzxl7KikaiQtr1ipLwNCYNA==} + dcql@0.2.13: + resolution: {integrity: sha512-XfePsSz9ULj9HH3VFNguzK/xlFnliKDX2iUDb1tIrn97S+TfftcFo+jipw16m9jPlWLhhBx48QniF0D8KotIWA==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -13835,7 +13835,7 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.12(typescript@5.4.5): + dcql@0.2.13(typescript@5.4.5): dependencies: valibot: 0.37.0(typescript@5.4.5) transitivePeerDependencies: From c654a7bce3dd659d48d7cf3fdfa5d6f23b23a3f4 Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Sun, 24 Nov 2024 14:07:27 +0100 Subject: [PATCH 08/48] fix: check if oid4vp defined Signed-off-by: Timo Glastra --- .../lib/authorization-response/AuthorizationResponse.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index c1c71212..09d91a6c 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -207,8 +207,8 @@ export class AuthorizationResponse { state, correlationId: verifyOpts.correlationId, ...(this.idToken && { idToken: verifiedIdToken }), - ...(oid4vp.presentationExchange && { oid4vpSubmission: oid4vp.presentationExchange }), - ...(oid4vp.dcql && { oid4vpSubmissionDcql: oid4vp.dcql }), + ...(oid4vp?.presentationExchange && { oid4vpSubmission: oid4vp.presentationExchange }), + ...(oid4vp?.dcql && { oid4vpSubmissionDcql: oid4vp.dcql }), } } From 76be4cc85ae2be951574385ba9a6f0aa1c62d18f Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Mon, 25 Nov 2024 14:43:26 +0100 Subject: [PATCH 09/48] fix: update dcql and incorporate feedback --- .../siop-oid4vp/lib/authorization-request/Payload.ts | 4 ++-- .../authorization-response/AuthorizationResponse.ts | 12 +++++------- .../siop-oid4vp/lib/authorization-response/Dcql.ts | 4 ++-- .../lib/authorization-response/OpenID4VP.ts | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index b21d7c70..07290006 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -35,13 +35,13 @@ export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadO return { ...(opts.id_token ? { id_token: opts.id_token } : {}), - ...((opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri || opts.vp_token.dcql_query) && { + ...((opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri) && { vp_token: { ...(!opts.vp_token.presentation_definition_uri && { presentation_definition: opts.vp_token.presentation_definition }), ...(opts.vp_token.presentation_definition_uri && { presentation_definition_uri: opts.vp_token.presentation_definition_uri }), - ...(opts.vp_token.dcql_query && { dcql_query: opts.vp_token.dcql_query }), }, }), + ...(opts.vp_token.dcql_query && { vp_token: { dcql_query: opts.vp_token.dcql_query } }), } } diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 09d91a6c..9bb0dcf4 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -130,7 +130,7 @@ export class AuthorizationResponse { if (responseOpts.presentationExchange) { const wrappedPresentations = response.payload.vp_token - ? await extractPresentationsFromVpToken(response.payload.vp_token, { + ? extractPresentationsFromVpToken(response.payload.vp_token, { hasher: verifyOpts.hasher, }) : [] @@ -144,14 +144,12 @@ export class AuthorizationResponse { hasher: verifyOpts.hasher, }, }) - } else { - const dcqlQuery = verifiedAuthorizationRequest.dcqlQuery - if (!dcqlQuery) { - throw new Error('vp_token is present, but no presentation definitions or dcql query provided') - } - assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, dcqlQuery, { + } else if (verifiedAuthorizationRequest.dcqlQuery) { + assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, verifiedAuthorizationRequest.dcqlQuery, { hasher: verifyOpts.hasher, }) + } else { + throw new Error('vp_token is present, but no presentation definitions or dcql query provided') } return response diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index 77ab1da5..7740fdb3 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -43,10 +43,10 @@ export const getDcqlPresentationResult = (record: DcqlPresentation | string, dcq if (p.format === 'mso_mdoc') { return [ queryId, - { credentialFormat: 'mso_mdoc', doctype: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential, + { credential_format: 'mso_mdoc', doctype: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential, ] } else if (p.format === 'vc+sd-jwt') { - return [queryId, { credentialFormat: 'vc+sd-jwt', vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] + return [queryId, { credential_format: 'vc+sd-jwt', vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] } else { throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index d1177ef4..d4fe8b9d 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -113,7 +113,7 @@ export const verifyPresentations = async ( } } else { const presentations = authorizationResponse.payload.vp_token - ? await extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) + ? extractPresentationsFromVpToken(authorizationResponse.payload.vp_token, { hasher: verifyOpts.hasher }) : [] wrappedPresentations = Array.isArray(presentations) ? presentations : [presentations] diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 937ce385..acb5d152 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.13", + "dcql": "^0.2.15", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.279", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4e47bc6..4b704bde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.13 - version: 0.2.13(typescript@5.4.5) + specifier: ^0.2.15 + version: 0.2.16(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -1867,7 +1867,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + engines: {'0': node >=0.10.0} '@expo/cli@0.7.3': resolution: {integrity: sha512-uMGHbAhApqXR2sd1KPhgvpbOhBBnspad8msEqHleT2PHXwKIwTUDzBGO9+jdOAWwCx2MJfw3+asYjzoD3DN9Bg==} @@ -4015,8 +4015,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.13: - resolution: {integrity: sha512-XfePsSz9ULj9HH3VFNguzK/xlFnliKDX2iUDb1tIrn97S+TfftcFo+jipw16m9jPlWLhhBx48QniF0D8KotIWA==} + dcql@0.2.16: + resolution: {integrity: sha512-sZpx8QZYc/vdPsOy0PyFWPNmTrDTPyLGsV0wPJJ6u/F+RFkQlw5LHV4fIfzPefdDKUF5YvGm3oDiBt3qzz9/zg==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -13835,7 +13835,7 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.13(typescript@5.4.5): + dcql@0.2.16(typescript@5.4.5): dependencies: valibot: 0.37.0(typescript@5.4.5) transitivePeerDependencies: From d7cc1e7342280370e9a4bef023e1b88ac735f412 Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Tue, 26 Nov 2024 09:59:27 +0100 Subject: [PATCH 10/48] feat: update dcql --- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index acb5d152..fb3df1a0 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "^0.2.15", + "dcql": "0.2.16", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.279", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b704bde..ef85fa2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,7 +461,7 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: ^0.2.15 + specifier: 0.2.16 version: 0.2.16(typescript@5.4.5) debug: specifier: ^4.3.5 @@ -2535,6 +2535,7 @@ packages: '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22': resolution: {integrity: sha512-uAZZExVy+ug9JLircejWa5eLtAZ7bnBP6xb7DO2+86LRsHNLh2k2jMWJYxp+iWtGHTsh6RYsZl14ScQLvjiQ/A==} + bundledDependencies: [] '@sphereon/pex-models@2.3.1': resolution: {integrity: sha512-SByU4cJ0XYA6VZQ/L6lsSiRcFtBPHbFioCeQ4GP7/W/jQ+PSBD7uK2oTnKQ9/0iEiMK/6JYqhKgLs4a9UX3UTQ==} From ad19797805d68855d902afcf586d521927654adc Mon Sep 17 00:00:00 2001 From: Martin Auer Date: Tue, 26 Nov 2024 10:00:10 +0100 Subject: [PATCH 11/48] feat: update dcql --- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index fb3df1a0..dbe0097d 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.24", - "dcql": "0.2.16", + "dcql": "0.2.17", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-next.279", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef85fa2a..82bfd10d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: 0.2.16 - version: 0.2.16(typescript@5.4.5) + specifier: 0.2.17 + version: 0.2.17(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -4016,8 +4016,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.16: - resolution: {integrity: sha512-sZpx8QZYc/vdPsOy0PyFWPNmTrDTPyLGsV0wPJJ6u/F+RFkQlw5LHV4fIfzPefdDKUF5YvGm3oDiBt3qzz9/zg==} + dcql@0.2.17: + resolution: {integrity: sha512-YKNJR2anEiWooUCg7cJt/QmSFxpBS+SJQurcsNA60+8qUrjOuroh1Wd+lka/yOAV2VUdRzdNY6ISouxTV6SUaQ==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -8322,16 +8322,16 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@0.37.0: - resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + valibot@0.42.1: + resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: typescript: '>=5' peerDependenciesMeta: typescript: optional: true - valibot@0.42.1: - resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} + valibot@1.0.0-beta.8: + resolution: {integrity: sha512-OPAwJZtowb0j91b+bd77+ny7D1VVzsCzD7Jl9waLUlMprTsfI9Y3HHbW3hAQD7wKDKHsmGEesuiYWaYvcZL2wg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -13836,9 +13836,9 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.16(typescript@5.4.5): + dcql@0.2.17(typescript@5.4.5): dependencies: - valibot: 0.37.0(typescript@5.4.5) + valibot: 1.0.0-beta.8(typescript@5.4.5) transitivePeerDependencies: - typescript @@ -19309,14 +19309,14 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@0.37.0(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - valibot@0.42.1(typescript@5.5.3): optionalDependencies: typescript: 5.5.3 + valibot@1.0.0-beta.8(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + valid-url@1.0.9: {} validate-npm-package-license@3.0.4: From 33e0be728e0cee17be59066818957c668587e2ed Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Thu, 5 Dec 2024 11:41:53 +0100 Subject: [PATCH 12/48] chore: Added dcql to resolutions since there are major changes in the API. --- package.json | 1 + packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9339e342..762975d3 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "resolutions": { "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "dcql": "0.2.11", "node-fetch": "2.6.12" }, "prettier": { diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index a7d71c96..a1aae703 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.28", - "dcql": "^0.2.11", + "dcql": "0.2.11", "@sphereon/pex-models": "^2.3.1", "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ac67b6b..52d346bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,7 @@ settings: overrides: '@sphereon/ssi-types': 0.30.2-feature.mdoc.funke2.367 + dcql: 0.2.11 node-fetch: 2.6.12 importers: @@ -461,6 +462,9 @@ importers: cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) + dcql: + specifier: 0.2.11 + version: 0.2.11(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -2542,6 +2546,7 @@ packages: '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.10': resolution: {integrity: sha512-mHH7I6fWdztaNjguGJOLaerXWnQymQ/xKQ8NqClIXoI2PJNgmpQG6DxFcLRs1aYyWg1iY8bPliLJi41u94KdCA==} + bundledDependencies: [] '@sphereon/pex-models@2.3.1': resolution: {integrity: sha512-SByU4cJ0XYA6VZQ/L6lsSiRcFtBPHbFioCeQ4GP7/W/jQ+PSBD7uK2oTnKQ9/0iEiMK/6JYqhKgLs4a9UX3UTQ==} @@ -4013,6 +4018,9 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dcql@0.2.11: + resolution: {integrity: sha512-hR8MuSx49b7JPoZztcFMSKEHc6iEE4l/Zs6aUsvMCWVa3qFWpuJRiJEp5Rh2+UkCAhsce94fbDpMdBTcS9zn7g==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -8372,6 +8380,14 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + valibot@0.37.0: + resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + valibot@0.42.1: resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: @@ -13898,6 +13914,12 @@ snapshots: dayjs@1.11.13: {} + dcql@0.2.11(typescript@5.4.5): + dependencies: + valibot: 0.37.0(typescript@5.4.5) + transitivePeerDependencies: + - typescript + debug@2.6.9: dependencies: ms: 2.0.0 @@ -19558,6 +19580,10 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + valibot@0.37.0(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + valibot@0.42.1(typescript@5.5.3): optionalDependencies: typescript: 5.5.3 From 10fd2b1c4dcd919faeb643bab7b622f8eef73873 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Mon, 9 Dec 2024 14:33:19 +0100 Subject: [PATCH 13/48] chore: Fixed broken dependencies --- package.json | 2 +- packages/callback-example/package.json | 2 +- packages/client/package.json | 2 +- packages/common/package.json | 2 +- packages/issuer-rest/package.json | 2 +- packages/issuer/package.json | 2 +- packages/oid4vci-common/package.json | 2 +- .../AuthorizationRequestPayloadVD11.schema.ts | 82 +---------------- ...ationRequestPayloadVD12OID4VPD18.schema.ts | 82 +---------------- ...ationRequestPayloadVD12OID4VPD20.schema.ts | 82 +---------------- .../AuthorizationRequestPayloadVID1.schema.ts | 82 +---------------- packages/siop-oid4vp/package.json | 4 +- pnpm-lock.yaml | 91 +++++-------------- 13 files changed, 52 insertions(+), 385 deletions(-) diff --git a/package.json b/package.json index 762975d3..3eccf5f6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "resolutions": { - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../SSI-SDK/packages/ssi-types", "dcql": "0.2.11", "node-fetch": "2.6.12" }, diff --git a/packages/callback-example/package.json b/packages/callback-example/package.json index 515af167..64c6ffd9 100644 --- a/packages/callback-example/package.json +++ b/packages/callback-example/package.json @@ -19,7 +19,7 @@ "@sphereon/oid4vci-client": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "jose": "^4.10.0" }, "devDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index 42c78f5f..cb1db4dc 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,7 +17,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "cross-fetch": "^3.1.8", "debug": "^4.3.5" }, diff --git a/packages/common/package.json b/packages/common/package.json index 2f134698..fe28aac1 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -10,7 +10,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "jwt-decode": "^4.0.0", "sha.js": "^2.4.11", "uint8arrays": "3.1.1", diff --git a/packages/issuer-rest/package.json b/packages/issuer-rest/package.json index 909e1f0e..f06fb058 100644 --- a/packages/issuer-rest/package.json +++ b/packages/issuer-rest/package.json @@ -15,7 +15,7 @@ "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", "@sphereon/ssi-express-support": "0.30.2-feature.mdoc.funke2.367", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "body-parser": "^1.20.2", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/packages/issuer/package.json b/packages/issuer/package.json index ea56dee2..2b5b6934 100644 --- a/packages/issuer/package.json +++ b/packages/issuer/package.json @@ -12,7 +12,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "uuid": "^9.0.0" }, "peerDependencies": { diff --git a/packages/oid4vci-common/package.json b/packages/oid4vci-common/package.json index 285a6a31..d7731797 100644 --- a/packages/oid4vci-common/package.json +++ b/packages/oid4vci-common/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@sphereon/oid4vc-common": "workspace:*", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "cross-fetch": "^3.1.8", "debug": "^4.3.5", "jwt-decode": "^4.0.0", diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD11.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD11.schema.ts index 020c0299..0fb7ce3a 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD11.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD11.schema.ts @@ -699,9 +699,6 @@ export const AuthorizationRequestPayloadVD11SchemaObj = { "type": "string" } }, - "required": [ - "type" - ], "additionalProperties": false }, "OneOfNumberStringBoolean": { @@ -934,81 +931,15 @@ export const AuthorizationRequestPayloadVD11SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" - }, - "items": { - "$ref": "#/definitions/FilterV2BaseItems" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - "FilterV2Base": { - "type": "object", - "properties": { - "const": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - }, - "enum": { - "type": "array", - "items": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - } - }, - "exclusiveMinimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "format": { - "type": "string" - }, - "formatMaximum": { - "type": "string" - }, - "formatMinimum": { - "type": "string" - }, - "formatExclusiveMaximum": { - "type": "string" - }, - "formatExclusiveMinimum": { - "type": "string" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "minimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "maximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "not": { - "type": "object" - }, - "pattern": { - "type": "string" - }, - "type": { - "type": "string" - }, - "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, "additionalProperties": false }, - "FilterV2BaseItems": { + "FilterV2Items": { "type": "object", "properties": { "const": { @@ -1063,15 +994,12 @@ export const AuthorizationRequestPayloadVD11SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, - "required": [ - "type" - ], "additionalProperties": false } } diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD18.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD18.schema.ts index bb6429d1..3191b080 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD18.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD18.schema.ts @@ -705,9 +705,6 @@ export const AuthorizationRequestPayloadVD12OID4VPD18SchemaObj = { "type": "string" } }, - "required": [ - "type" - ], "additionalProperties": false }, "OneOfNumberStringBoolean": { @@ -940,81 +937,15 @@ export const AuthorizationRequestPayloadVD12OID4VPD18SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" - }, - "items": { - "$ref": "#/definitions/FilterV2BaseItems" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - "FilterV2Base": { - "type": "object", - "properties": { - "const": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - }, - "enum": { - "type": "array", - "items": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - } - }, - "exclusiveMinimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "format": { - "type": "string" - }, - "formatMaximum": { - "type": "string" - }, - "formatMinimum": { - "type": "string" - }, - "formatExclusiveMaximum": { - "type": "string" - }, - "formatExclusiveMinimum": { - "type": "string" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "minimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "maximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "not": { - "type": "object" - }, - "pattern": { - "type": "string" - }, - "type": { - "type": "string" - }, - "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, "additionalProperties": false }, - "FilterV2BaseItems": { + "FilterV2Items": { "type": "object", "properties": { "const": { @@ -1069,15 +1000,12 @@ export const AuthorizationRequestPayloadVD12OID4VPD18SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, - "required": [ - "type" - ], "additionalProperties": false }, "ClientIdSchemeOID4VPD18": { diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts index 14e4d863..eeee9e8a 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVD12OID4VPD20.schema.ts @@ -708,9 +708,6 @@ export const AuthorizationRequestPayloadVD12OID4VPD20SchemaObj = { "type": "string" } }, - "required": [ - "type" - ], "additionalProperties": false }, "OneOfNumberStringBoolean": { @@ -943,81 +940,15 @@ export const AuthorizationRequestPayloadVD12OID4VPD20SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" - }, - "items": { - "$ref": "#/definitions/FilterV2BaseItems" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - "FilterV2Base": { - "type": "object", - "properties": { - "const": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - }, - "enum": { - "type": "array", - "items": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - } - }, - "exclusiveMinimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "format": { - "type": "string" - }, - "formatMaximum": { - "type": "string" - }, - "formatMinimum": { - "type": "string" - }, - "formatExclusiveMaximum": { - "type": "string" - }, - "formatExclusiveMinimum": { - "type": "string" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "minimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "maximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "not": { - "type": "object" - }, - "pattern": { - "type": "string" - }, - "type": { - "type": "string" - }, - "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, "additionalProperties": false }, - "FilterV2BaseItems": { + "FilterV2Items": { "type": "object", "properties": { "const": { @@ -1072,15 +1003,12 @@ export const AuthorizationRequestPayloadVD12OID4VPD20SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, - "required": [ - "type" - ], "additionalProperties": false }, "ClientIdSchemeOID4VPD20": { diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts index 59cc00bf..61931b35 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationRequestPayloadVID1.schema.ts @@ -704,9 +704,6 @@ export const AuthorizationRequestPayloadVID1SchemaObj = { "type": "string" } }, - "required": [ - "type" - ], "additionalProperties": false }, "OneOfNumberStringBoolean": { @@ -939,81 +936,15 @@ export const AuthorizationRequestPayloadVID1SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" - }, - "items": { - "$ref": "#/definitions/FilterV2BaseItems" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - "FilterV2Base": { - "type": "object", - "properties": { - "const": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - }, - "enum": { - "type": "array", - "items": { - "$ref": "#/definitions/OneOfNumberStringBoolean" - } - }, - "exclusiveMinimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "exclusiveMaximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "format": { - "type": "string" - }, - "formatMaximum": { - "type": "string" - }, - "formatMinimum": { - "type": "string" - }, - "formatExclusiveMaximum": { - "type": "string" - }, - "formatExclusiveMinimum": { - "type": "string" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "minimum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "maximum": { - "$ref": "#/definitions/OneOfNumberString" - }, - "not": { - "type": "object" - }, - "pattern": { - "type": "string" - }, - "type": { - "type": "string" - }, - "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, "additionalProperties": false }, - "FilterV2BaseItems": { + "FilterV2Items": { "type": "object", "properties": { "const": { @@ -1068,15 +999,12 @@ export const AuthorizationRequestPayloadVID1SchemaObj = { "type": "string" }, "contains": { - "$ref": "#/definitions/FilterV2Base" + "$ref": "#/definitions/FilterV2" }, "items": { - "$ref": "#/definitions/FilterV2BaseItems" + "$ref": "#/definitions/FilterV2Items" } }, - "required": [ - "type" - ], "additionalProperties": false } } diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index a1aae703..9c317640 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -19,8 +19,8 @@ "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.28", "dcql": "0.2.11", - "@sphereon/pex-models": "^2.3.1", - "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.367", + "@sphereon/pex-models": "^2.3.2", + "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", "cross-fetch": "^4.0.0", "debug": "^4.3.5", "events": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52d346bb..6e6aadee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@sphereon/ssi-types': 0.30.2-feature.mdoc.funke2.367 + '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types dcql: 0.2.11 node-fetch: 2.6.12 @@ -77,8 +77,8 @@ importers: specifier: workspace:* version: link:../issuer '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types jose: specifier: ^4.10.0 version: 4.15.9 @@ -120,8 +120,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -205,8 +205,8 @@ importers: packages/common: dependencies: '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types jwt-decode: specifier: ^4.0.0 version: 4.0.0 @@ -273,8 +273,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -316,8 +316,8 @@ importers: specifier: 0.30.2-feature.mdoc.funke2.367 version: 0.30.2-feature.mdoc.funke2.367 '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -408,8 +408,8 @@ importers: specifier: workspace:* version: link:../common '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -454,11 +454,11 @@ importers: specifier: 5.0.0-unstable.28 version: 5.0.0-unstable.28 '@sphereon/pex-models': - specifier: ^2.3.1 - version: 2.3.1 + specifier: ^2.3.2 + version: 2.3.2 '@sphereon/ssi-types': - specifier: 0.30.2-feature.mdoc.funke2.367 - version: 0.30.2-feature.mdoc.funke2.367 + specifier: link:../../../SSI-SDK/packages/ssi-types + version: link:../../../SSI-SDK/packages/ssi-types cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) @@ -2120,14 +2120,6 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@js-joda/core@5.6.3': - resolution: {integrity: sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA==} - - '@js-joda/timezone@2.3.0': - resolution: {integrity: sha512-DHXdNs0SydSqC5f0oRJPpTcNfnpRojgBqMCFupQFv6WgeZAjU3DBx+A7JtaGPP3dHrP2Odi2N8Vf+uAm/8ynCQ==} - peerDependencies: - '@js-joda/core': '>=1.11.0' - '@lerna/create@8.1.9': resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==} engines: {node: '>=18.0.0'} @@ -2544,12 +2536,8 @@ packages: react-native-securerandom: optional: true - '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.10': - resolution: {integrity: sha512-mHH7I6fWdztaNjguGJOLaerXWnQymQ/xKQ8NqClIXoI2PJNgmpQG6DxFcLRs1aYyWg1iY8bPliLJi41u94KdCA==} - bundledDependencies: [] - - '@sphereon/pex-models@2.3.1': - resolution: {integrity: sha512-SByU4cJ0XYA6VZQ/L6lsSiRcFtBPHbFioCeQ4GP7/W/jQ+PSBD7uK2oTnKQ9/0iEiMK/6JYqhKgLs4a9UX3UTQ==} + '@sphereon/pex-models@2.3.2': + resolution: {integrity: sha512-foFxfLkRwcn/MOp/eht46Q7wsvpQGlO7aowowIIb5Tz9u97kYZ2kz6K2h2ODxWuv5CRA7Q0MY8XUBGE2lfOhOQ==} '@sphereon/pex@5.0.0-unstable.28': resolution: {integrity: sha512-zxHCWAc7fKppS7XX0zxnI4TF+Rdjax8pHc3exrYzn3t59dlv5siEAeYdtFrWJT4UVB5wTGzIEufzV5r+tfjelg==} @@ -2572,9 +2560,6 @@ packages: '@sphereon/ssi-sdk-ext.key-utils@0.23.0': resolution: {integrity: sha512-BfULXvQmcUrBq2DqYxJHKnEoB2d5icu3TJ9GP2aP1WybSULTjL96Wv5r7QKgktcodKaL+F+oQ7r8sC9qBl1exw==} - '@sphereon/ssi-types@0.30.2-feature.mdoc.funke2.367': - resolution: {integrity: sha512-+acZDnAB08PjhrNX+0sJuGK6X3AN2zZ6dvXjfWCXovWjJwcKJBBGR+nfvguBbefR9aaB8SKPAkDFhQ/U/I7byg==} - '@sphereon/wellknown-dids-client@0.1.3': resolution: {integrity: sha512-TAT24L3RoXD8ocrkTcsz7HuJmgjNjdoV6IXP1p3DdaI/GqkynytXE3J1+F7vUFMRYwY5nW2RaXSgDQhrFJemaA==} @@ -4774,9 +4759,6 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} - format-util@1.0.5: - resolution: {integrity: sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==} - formidable@2.1.2: resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} @@ -11158,12 +11140,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@js-joda/core@5.6.3': {} - - '@js-joda/timezone@2.3.0(@js-joda/core@5.6.3)': - dependencies: - '@js-joda/core': 5.6.3 - '@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.5.3)': dependencies: '@npmcli/arborist': 7.5.4 @@ -11888,13 +11864,7 @@ snapshots: expo: 48.0.21(@babel/core@7.26.0)(encoding@0.1.13) react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) - '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.10': - dependencies: - '@js-joda/core': 5.6.3 - '@js-joda/timezone': 2.3.0(@js-joda/core@5.6.3) - format-util: 1.0.5 - - '@sphereon/pex-models@2.3.1': {} + '@sphereon/pex-models@2.3.2': {} '@sphereon/pex@5.0.0-unstable.28': dependencies: @@ -11902,15 +11872,13 @@ snapshots: '@sd-jwt/decode': 0.7.2 '@sd-jwt/present': 0.7.2 '@sd-jwt/types': 0.7.2 - '@sphereon/pex-models': 2.3.1 - '@sphereon/ssi-types': 0.30.2-feature.mdoc.funke2.367 + '@sphereon/pex-models': 2.3.2 + '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) jwt-decode: 3.1.2 nanoid: 3.3.7 uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color '@sphereon/ssi-express-support@0.30.2-feature.mdoc.funke2.367': dependencies: @@ -11955,24 +11923,13 @@ snapshots: - react-native-securerandom - supports-color - '@sphereon/ssi-types@0.30.2-feature.mdoc.funke2.367': - dependencies: - '@sd-jwt/decode': 0.7.2 - '@sphereon/kmp-mdoc-core': 0.2.0-SNAPSHOT.10 - debug: 4.3.7 - events: 3.3.0 - jwt-decode: 3.1.2 - transitivePeerDependencies: - - supports-color - '@sphereon/wellknown-dids-client@0.1.3(encoding@0.1.13)': dependencies: - '@sphereon/ssi-types': 0.30.2-feature.mdoc.funke2.367 + '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types cross-fetch: 3.1.8(encoding@0.1.13) jwt-decode: 3.1.2 transitivePeerDependencies: - encoding - - supports-color '@stablelib/aead@1.0.1': {} @@ -14981,8 +14938,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - format-util@1.0.5: {} - formidable@2.1.2: dependencies: dezalgo: 1.0.4 From fc238f42e2a1a3427af82385b61cbdc2485bac31 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 11 Dec 2024 16:11:13 +0100 Subject: [PATCH 14/48] refactor: Removed local dependencies --- package.json | 5 +- packages/callback-example/package.json | 2 +- packages/client/package.json | 2 +- packages/common/package.json | 2 +- packages/issuer-rest/package.json | 2 +- packages/issuer/package.json | 2 +- packages/oid4vci-common/package.json | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 80 ++++++++++++++++++++------ 9 files changed, 73 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 3eccf5f6..3fb16fb7 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "resolutions": { - "@sphereon/ssi-types": "link:../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "dcql": "0.2.11", "node-fetch": "2.6.12" }, @@ -65,5 +65,6 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ] + ], + "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" } diff --git a/packages/callback-example/package.json b/packages/callback-example/package.json index 64c6ffd9..2b771138 100644 --- a/packages/callback-example/package.json +++ b/packages/callback-example/package.json @@ -19,7 +19,7 @@ "@sphereon/oid4vci-client": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "jose": "^4.10.0" }, "devDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index cb1db4dc..9617ba91 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,7 +17,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "cross-fetch": "^3.1.8", "debug": "^4.3.5" }, diff --git a/packages/common/package.json b/packages/common/package.json index fe28aac1..e7a0f0d8 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -10,7 +10,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "jwt-decode": "^4.0.0", "sha.js": "^2.4.11", "uint8arrays": "3.1.1", diff --git a/packages/issuer-rest/package.json b/packages/issuer-rest/package.json index f06fb058..5a141b03 100644 --- a/packages/issuer-rest/package.json +++ b/packages/issuer-rest/package.json @@ -15,7 +15,7 @@ "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", "@sphereon/ssi-express-support": "0.30.2-feature.mdoc.funke2.367", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "body-parser": "^1.20.2", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/packages/issuer/package.json b/packages/issuer/package.json index 2b5b6934..3eae5336 100644 --- a/packages/issuer/package.json +++ b/packages/issuer/package.json @@ -12,7 +12,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "uuid": "^9.0.0" }, "peerDependencies": { diff --git a/packages/oid4vci-common/package.json b/packages/oid4vci-common/package.json index d7731797..1fd88ead 100644 --- a/packages/oid4vci-common/package.json +++ b/packages/oid4vci-common/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@sphereon/oid4vc-common": "workspace:*", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "cross-fetch": "^3.1.8", "debug": "^4.3.5", "jwt-decode": "^4.0.0", diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 9c317640..4ca497ba 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -20,7 +20,7 @@ "@sphereon/pex": "5.0.0-unstable.28", "dcql": "0.2.11", "@sphereon/pex-models": "^2.3.2", - "@sphereon/ssi-types": "link:../../SSI-SDK/packages/ssi-types", + "@sphereon/ssi-types": "0.32.0", "cross-fetch": "^4.0.0", "debug": "^4.3.5", "events": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e6aadee..71d5d012 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types + '@sphereon/ssi-types': 0.32.0 dcql: 0.2.11 node-fetch: 2.6.12 @@ -77,8 +77,8 @@ importers: specifier: workspace:* version: link:../issuer '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 jose: specifier: ^4.10.0 version: 4.15.9 @@ -120,8 +120,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -205,8 +205,8 @@ importers: packages/common: dependencies: '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 jwt-decode: specifier: ^4.0.0 version: 4.0.0 @@ -273,8 +273,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -316,8 +316,8 @@ importers: specifier: 0.30.2-feature.mdoc.funke2.367 version: 0.30.2-feature.mdoc.funke2.367 '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -408,8 +408,8 @@ importers: specifier: workspace:* version: link:../common '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -457,8 +457,8 @@ importers: specifier: ^2.3.2 version: 2.3.2 '@sphereon/ssi-types': - specifier: link:../../../SSI-SDK/packages/ssi-types - version: link:../../../SSI-SDK/packages/ssi-types + specifier: 0.32.0 + version: 0.32.0 cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) @@ -2120,6 +2120,14 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@js-joda/core@5.6.3': + resolution: {integrity: sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA==} + + '@js-joda/timezone@2.3.0': + resolution: {integrity: sha512-DHXdNs0SydSqC5f0oRJPpTcNfnpRojgBqMCFupQFv6WgeZAjU3DBx+A7JtaGPP3dHrP2Odi2N8Vf+uAm/8ynCQ==} + peerDependencies: + '@js-joda/core': '>=1.11.0' + '@lerna/create@8.1.9': resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==} engines: {node: '>=18.0.0'} @@ -2536,6 +2544,10 @@ packages: react-native-securerandom: optional: true + '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': + resolution: {integrity: sha512-QXJ6R8ENiZV2rPMbn06cw5JKwqUYN1kzVRbYfONqE1PEXx1noQ4md7uxr2zSczi0ubKkNcbyYDNtIMTZIhGzmQ==} + bundledDependencies: [] + '@sphereon/pex-models@2.3.2': resolution: {integrity: sha512-foFxfLkRwcn/MOp/eht46Q7wsvpQGlO7aowowIIb5Tz9u97kYZ2kz6K2h2ODxWuv5CRA7Q0MY8XUBGE2lfOhOQ==} @@ -2560,6 +2572,9 @@ packages: '@sphereon/ssi-sdk-ext.key-utils@0.23.0': resolution: {integrity: sha512-BfULXvQmcUrBq2DqYxJHKnEoB2d5icu3TJ9GP2aP1WybSULTjL96Wv5r7QKgktcodKaL+F+oQ7r8sC9qBl1exw==} + '@sphereon/ssi-types@0.32.0': + resolution: {integrity: sha512-v5yC/bj1nvHE30cYMMqmjz2KHPpXj3OL8ZwnZQTiAMISS4DOVTjpYt0qZgb4eA1Lsdw2smd1bNYyVsOEJ02PAw==} + '@sphereon/wellknown-dids-client@0.1.3': resolution: {integrity: sha512-TAT24L3RoXD8ocrkTcsz7HuJmgjNjdoV6IXP1p3DdaI/GqkynytXE3J1+F7vUFMRYwY5nW2RaXSgDQhrFJemaA==} @@ -4759,6 +4774,9 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} + format-util@1.0.5: + resolution: {integrity: sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==} + formidable@2.1.2: resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} @@ -11140,6 +11158,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@js-joda/core@5.6.3': {} + + '@js-joda/timezone@2.3.0(@js-joda/core@5.6.3)': + dependencies: + '@js-joda/core': 5.6.3 + '@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.5.3)': dependencies: '@npmcli/arborist': 7.5.4 @@ -11864,6 +11888,12 @@ snapshots: expo: 48.0.21(@babel/core@7.26.0)(encoding@0.1.13) react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) + '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': + dependencies: + '@js-joda/core': 5.6.3 + '@js-joda/timezone': 2.3.0(@js-joda/core@5.6.3) + format-util: 1.0.5 + '@sphereon/pex-models@2.3.2': {} '@sphereon/pex@5.0.0-unstable.28': @@ -11873,12 +11903,14 @@ snapshots: '@sd-jwt/present': 0.7.2 '@sd-jwt/types': 0.7.2 '@sphereon/pex-models': 2.3.2 - '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types + '@sphereon/ssi-types': 0.32.0 ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) jwt-decode: 3.1.2 nanoid: 3.3.7 uint8arrays: 3.1.1 + transitivePeerDependencies: + - supports-color '@sphereon/ssi-express-support@0.30.2-feature.mdoc.funke2.367': dependencies: @@ -11923,13 +11955,25 @@ snapshots: - react-native-securerandom - supports-color + '@sphereon/ssi-types@0.32.0': + dependencies: + '@sd-jwt/decode': 0.7.2 + '@sphereon/kmp-mdoc-core': 0.2.0-SNAPSHOT.26 + debug: 4.3.7 + events: 3.3.0 + jwt-decode: 3.1.2 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - supports-color + '@sphereon/wellknown-dids-client@0.1.3(encoding@0.1.13)': dependencies: - '@sphereon/ssi-types': link:../SSI-SDK/packages/ssi-types + '@sphereon/ssi-types': 0.32.0 cross-fetch: 3.1.8(encoding@0.1.13) jwt-decode: 3.1.2 transitivePeerDependencies: - encoding + - supports-color '@stablelib/aead@1.0.1': {} @@ -14938,6 +14982,8 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + format-util@1.0.5: {} + formidable@2.1.2: dependencies: dezalgo: 1.0.4 From 47b9205caeb503bc90b4f4674c50a745324a17f4 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 11 Dec 2024 16:13:17 +0100 Subject: [PATCH 15/48] refactor: Removed packageManager from the package.json --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 3fb16fb7..bb28456b 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,5 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ], - "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" + ] } From fa3e1b892948ee9c272f880e806da17daacde077 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 17 Dec 2024 12:20:32 +0100 Subject: [PATCH 16/48] chore: lockfile --- pnpm-lock.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71d5d012..f12956d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -257,9 +257,6 @@ importers: '@types/jest': specifier: ^29.5.12 version: 29.5.14 - '@types/jwt-decode': - specifier: ^3.1.0 - version: 3.1.0 typescript: specifier: 5.4.5 version: 5.4.5 @@ -547,9 +544,6 @@ importers: '@types/jest': specifier: ^29.5.11 version: 29.5.14 - '@types/jwt-decode': - specifier: ^3.1.0 - version: 3.1.0 '@types/language-tags': specifier: ^1.0.4 version: 1.0.4 @@ -2857,10 +2851,6 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/jwt-decode@3.1.0': - resolution: {integrity: sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w==} - deprecated: This is a stub types definition. jwt-decode provides its own type definitions, so you do not need this installed. - '@types/language-tags@1.0.4': resolution: {integrity: sha512-20PQbifv3v/djCT+KlXybv0KqO5ofoR1qD1wkinN59kfggTPVTWGmPFgL/1yWuDyRcsQP/POvkqK+fnl5nOwTg==} @@ -12399,10 +12389,6 @@ snapshots: '@types/json5@0.0.29': {} - '@types/jwt-decode@3.1.0': - dependencies: - jwt-decode: 4.0.0 - '@types/language-tags@1.0.4': {} '@types/mime@1.3.5': {} From 9b7a2c394b7b592bc2c563e112d7f2ed3a7d6c94 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 17 Dec 2024 13:43:13 +0100 Subject: [PATCH 17/48] chore: use DcqlQuery object just like presentation_definition has an object --- package.json | 2 +- packages/callback-example/package.json | 2 +- packages/client/package.json | 2 +- packages/common/package.json | 2 +- packages/issuer-rest/package.json | 2 +- packages/issuer/package.json | 2 +- packages/oid4vci-common/package.json | 2 +- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 60 +++++++++++--------- packages/siop-oid4vp/lib/types/SIOP.types.ts | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 49 ++++++++-------- 11 files changed, 66 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index bb28456b..e1482a95 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "resolutions": { - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "dcql": "0.2.11", "node-fetch": "2.6.12" }, diff --git a/packages/callback-example/package.json b/packages/callback-example/package.json index 2b771138..bb1dd3e1 100644 --- a/packages/callback-example/package.json +++ b/packages/callback-example/package.json @@ -19,7 +19,7 @@ "@sphereon/oid4vci-client": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "jose": "^4.10.0" }, "devDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index 9617ba91..5e7acb8a 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,7 +17,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "cross-fetch": "^3.1.8", "debug": "^4.3.5" }, diff --git a/packages/common/package.json b/packages/common/package.json index e7a0f0d8..04ea2a3d 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -10,7 +10,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "jwt-decode": "^4.0.0", "sha.js": "^2.4.11", "uint8arrays": "3.1.1", diff --git a/packages/issuer-rest/package.json b/packages/issuer-rest/package.json index 5a141b03..5c3007e0 100644 --- a/packages/issuer-rest/package.json +++ b/packages/issuer-rest/package.json @@ -15,7 +15,7 @@ "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", "@sphereon/ssi-express-support": "0.30.2-feature.mdoc.funke2.367", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "body-parser": "^1.20.2", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/packages/issuer/package.json b/packages/issuer/package.json index 3eae5336..ea3d1f4f 100644 --- a/packages/issuer/package.json +++ b/packages/issuer/package.json @@ -12,7 +12,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "uuid": "^9.0.0" }, "peerDependencies": { diff --git a/packages/oid4vci-common/package.json b/packages/oid4vci-common/package.json index 1fd88ead..ffcfdb85 100644 --- a/packages/oid4vci-common/package.json +++ b/packages/oid4vci-common/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@sphereon/oid4vc-common": "workspace:*", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "cross-fetch": "^3.1.8", "debug": "^4.3.5", "jwt-decode": "^4.0.0", diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 6a321c3e..da222746 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -23,6 +23,7 @@ import { import { assignIfAuth, assignIfRequestObject, isTarget, isTargetOrNoTargets } from './Opts' import { RP } from './RP' import { IRPSessionManager } from './types' +import { DcqlQuery } from 'dcql' export class RPBuilder { requestObjectBy: ObjectBy @@ -226,73 +227,78 @@ export class RPBuilder { return this } - withDcqlQuery(dcqlQuery: string, targets?: PropertyTargets): RPBuilder { - this._authorizationRequestPayload.dcql_query = assignIfAuth( - { - propertyValue: dcqlQuery, - targets, - }, - false, - ) - this._requestObjectPayload.dcql_query = assignIfRequestObject( - { - propertyValue: dcqlQuery, - targets, - }, - true, - ) + withDcqlQuery(dcqlQuery: DcqlQuery, targets?: PropertyTargets): RPBuilder { + if (this.getSupportedRequestVersion() >= SupportedVersion.SIOPv2_D12_OID4VP_D20) { + this._authorizationRequestPayload.dcql_query = assignIfAuth( + { + propertyValue: dcqlQuery, + targets + }, + false + ) + this._requestObjectPayload.dcql_query = assignIfRequestObject( + { + propertyValue: dcqlQuery, + targets + }, + true + ) + } return this } - withPresentationDefinition(definitionOpts: { definition: IPresentationDefinition; definitionUri?: string }, targets?: PropertyTargets): RPBuilder { + withPresentationDefinition(definitionOpts: { + definition: IPresentationDefinition; + definitionUri?: string + }, targets?: PropertyTargets): RPBuilder { const { definition, definitionUri } = definitionOpts if (this.getSupportedRequestVersion() < SupportedVersion.SIOPv2_D11) { const definitionProperties = { presentation_definition: definition, - presentation_definition_uri: definitionUri, + presentation_definition_uri: definitionUri } const vp_token = { ...definitionProperties } if (isTarget(PropertyTarget.AUTHORIZATION_REQUEST, targets)) { this._authorizationRequestPayload.claims = { ...(this._authorizationRequestPayload.claims ? this._authorizationRequestPayload.claims : {}), - vp_token: vp_token, + vp_token: vp_token } } if (isTargetOrNoTargets(PropertyTarget.REQUEST_OBJECT, targets)) { this._requestObjectPayload.claims = { ...(this._requestObjectPayload.claims ? this._requestObjectPayload.claims : {}), - vp_token: vp_token, + vp_token: vp_token } } } else { this._authorizationRequestPayload.presentation_definition = assignIfAuth( { propertyValue: definition, - targets, + targets }, - false, + false ) this._authorizationRequestPayload.presentation_definition_uri = assignIfAuth( { propertyValue: definitionUri, - targets, + targets }, - true, + true ) this._requestObjectPayload.presentation_definition = assignIfRequestObject( { propertyValue: definition, - targets, + targets }, - true, + true ) this._requestObjectPayload.presentation_definition_uri = assignIfRequestObject( { propertyValue: definitionUri, - targets, + targets }, - true, + true ) } return this diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index 28705d5b..24622244 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -100,7 +100,7 @@ export interface AuthorizationRequestPayloadVD12OID4VPD20 presentation_definition_uri?: string client_id_scheme?: ClientIdSchemeOID4VPD20 response_uri?: string // New since OID4VP18 OPTIONAL. The Response URI to which the Wallet MUST send the Authorization Response using an HTTPS POST request as defined by the Response Mode direct_post. The Response URI receives all Authorization Response parameters as defined by the respective Response Type. When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error. - dcql_query?: string + dcql_query?: DcqlQuery } export type ClientIdSchemeOID4VPD18 = 'pre-registered' | 'redirect_uri' | 'entity_id' | 'did' diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 4e9ac139..2e98f766 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -20,7 +20,7 @@ "@sphereon/pex": "5.0.0-unstable.28", "dcql": "0.2.11", "@sphereon/pex-models": "^2.3.2", - "@sphereon/ssi-types": "0.32.0", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", "cross-fetch": "^4.0.0", "debug": "^4.3.5", "events": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f12956d5..73d98481 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@sphereon/ssi-types': 0.32.0 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 dcql: 0.2.11 node-fetch: 2.6.12 @@ -77,8 +77,8 @@ importers: specifier: workspace:* version: link:../issuer '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 jose: specifier: ^4.10.0 version: 4.15.9 @@ -120,8 +120,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -205,8 +205,8 @@ importers: packages/common: dependencies: '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 jwt-decode: specifier: ^4.0.0 version: 4.0.0 @@ -270,8 +270,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -313,8 +313,8 @@ importers: specifier: 0.30.2-feature.mdoc.funke2.367 version: 0.30.2-feature.mdoc.funke2.367 '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -405,8 +405,8 @@ importers: specifier: workspace:* version: link:../common '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -454,8 +454,8 @@ importers: specifier: ^2.3.2 version: 2.3.2 '@sphereon/ssi-types': - specifier: 0.32.0 - version: 0.32.0 + specifier: 0.32.1-feature.VDX.341.27 + version: 0.32.1-feature.VDX.341.27 cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) @@ -2540,7 +2540,6 @@ packages: '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': resolution: {integrity: sha512-QXJ6R8ENiZV2rPMbn06cw5JKwqUYN1kzVRbYfONqE1PEXx1noQ4md7uxr2zSczi0ubKkNcbyYDNtIMTZIhGzmQ==} - bundledDependencies: [] '@sphereon/pex-models@2.3.2': resolution: {integrity: sha512-foFxfLkRwcn/MOp/eht46Q7wsvpQGlO7aowowIIb5Tz9u97kYZ2kz6K2h2ODxWuv5CRA7Q0MY8XUBGE2lfOhOQ==} @@ -2566,8 +2565,8 @@ packages: '@sphereon/ssi-sdk-ext.key-utils@0.23.0': resolution: {integrity: sha512-BfULXvQmcUrBq2DqYxJHKnEoB2d5icu3TJ9GP2aP1WybSULTjL96Wv5r7QKgktcodKaL+F+oQ7r8sC9qBl1exw==} - '@sphereon/ssi-types@0.32.0': - resolution: {integrity: sha512-v5yC/bj1nvHE30cYMMqmjz2KHPpXj3OL8ZwnZQTiAMISS4DOVTjpYt0qZgb4eA1Lsdw2smd1bNYyVsOEJ02PAw==} + '@sphereon/ssi-types@0.32.1-feature.VDX.341.27': + resolution: {integrity: sha512-Mw72f13IckggZmQ2uXlcq/gHgwoV+Mqtj3/SyBHZrxkvAq9LpWynImrlgiQDkBGlvpQ3chZ/ju8pQIPDTIqFWA==} '@sphereon/wellknown-dids-client@0.1.3': resolution: {integrity: sha512-TAT24L3RoXD8ocrkTcsz7HuJmgjNjdoV6IXP1p3DdaI/GqkynytXE3J1+F7vUFMRYwY5nW2RaXSgDQhrFJemaA==} @@ -10027,7 +10026,7 @@ snapshots: '@digitalcredentials/bnid@2.1.2(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1))': dependencies: '@digitalcredentials/base58-universal': 1.0.1 - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) yargs: 15.4.1 transitivePeerDependencies: - react-native @@ -11876,7 +11875,7 @@ snapshots: webcrypto-shim: 0.1.7 optionalDependencies: expo: 48.0.21(@babel/core@7.26.0)(encoding@0.1.13) - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': dependencies: @@ -11893,7 +11892,7 @@ snapshots: '@sd-jwt/present': 0.7.2 '@sd-jwt/types': 0.7.2 '@sphereon/pex-models': 2.3.2 - '@sphereon/ssi-types': 0.32.0 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) jwt-decode: 3.1.2 @@ -11945,20 +11944,20 @@ snapshots: - react-native-securerandom - supports-color - '@sphereon/ssi-types@0.32.0': + '@sphereon/ssi-types@0.32.1-feature.VDX.341.27': dependencies: '@sd-jwt/decode': 0.7.2 '@sphereon/kmp-mdoc-core': 0.2.0-SNAPSHOT.26 debug: 4.3.7 events: 3.3.0 - jwt-decode: 3.1.2 + jwt-decode: 4.0.0 uint8arrays: 3.1.1 transitivePeerDependencies: - supports-color '@sphereon/wellknown-dids-client@0.1.3(encoding@0.1.13)': dependencies: - '@sphereon/ssi-types': 0.32.0 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 cross-fetch: 3.1.8(encoding@0.1.13) jwt-decode: 3.1.2 transitivePeerDependencies: @@ -18214,7 +18213,7 @@ snapshots: react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) optional: true - react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)): + react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)): dependencies: base64-js: 1.5.1 react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) From 9b4bb1f5263fba2a9cc0acf80811b37bca764670 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 17 Dec 2024 16:21:53 +0100 Subject: [PATCH 18/48] chore: only show DcqlQuery when present --- packages/siop-oid4vp/lib/rp/RP.ts | 8 ++++++-- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index 827db4c4..52981b78 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -424,8 +424,12 @@ export class RP { state, nonce, verification: mergeVerificationOpts(this._verifyResponseOptions, opts), - presentationDefinitions: opts?.presentationDefinitions ?? this._verifyResponseOptions.presentationDefinitions, - dcqlQuery: opts?.dcqlQuery ?? this._verifyResponseOptions.dcqlQuery, + ...(opts?.presentationDefinitions && !opts?.dcqlQuery && { + presentationDefinitions: this._verifyResponseOptions.presentationDefinitions + }), + ...(opts?.dcqlQuery && { + dcqlQuery: this._verifyResponseOptions.dcqlQuery + }) } } diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 6a321c3e..4e3c5f6c 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -241,10 +241,16 @@ export class RPBuilder { }, true, ) + this._authorizationRequestPayload.presentation_definition = undefined + this._requestObjectPayload.presentation_definition = undefined return this } withPresentationDefinition(definitionOpts: { definition: IPresentationDefinition; definitionUri?: string }, targets?: PropertyTargets): RPBuilder { + if(this._authorizationRequestPayload.dcql_query) { + return this + } + const { definition, definitionUri } = definitionOpts if (this.getSupportedRequestVersion() < SupportedVersion.SIOPv2_D11) { From 1020b5bb28fefcf4b3537d91fce4f8742d0a2ad5 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 17 Dec 2024 19:17:13 +0100 Subject: [PATCH 19/48] test: Added AuthenticationRequest and AuthenticationResponse queries --- .../AuthenticationRequest.request.spec.ts | 82 ++++++++++ .../AuthenticationResponse.response.spec.ts | 152 ++++++++++++++++++ 2 files changed, 234 insertions(+) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationRequest.request.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationRequest.request.spec.ts index 12e487b8..3b12ff26 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationRequest.request.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationRequest.request.spec.ts @@ -26,6 +26,7 @@ import { VERIFIERZ_PURPOSE_TO_VERIFY, VERIFIERZ_PURPOSE_TO_VERIFY_NL, } from './data/mockedData' +import { DcqlQuery } from 'dcql' const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const EXAMPLE_REFERENCE_URL = 'https://rp.acme.com/siop/jwts' @@ -671,4 +672,85 @@ describe('create Request JWT should', () => { } await expect(URI.fromOpts(opts)).rejects.toThrow(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) }) + + it('should succeed when requesting with a valid dcql query', async () => { + const dcqlQuery: DcqlQuery = { + credentials: [ + { + id: 'Credentials', + format: 'jwt_vc_json', + claims: [ + { + id: 'ID Card Credential', + path: ['$.issuer.id'], + values: ['did:example:issuer'], + }, + ], + }, + ], + } + const opts: CreateAuthorizationRequestOpts = { + version: SupportedVersion.SIOPv2_ID1, + payload: { + client_id: WELL_KNOWN_OPENID_FEDERATION, + scope: 'test', + response_type: 'vp_token', + request_object_signing_alg_values_supported: [SigningAlgo.ES256, SigningAlgo.EDDSA], + redirect_uri: EXAMPLE_REDIRECT_URL, + }, + requestObject: { + jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K }, + passBy: PassBy.REFERENCE, + reference_uri: EXAMPLE_REFERENCE_URL, + + createJwtCallback: getCreateJwtCallback({ + hexPrivateKey: HEX_KEY, + did: DID, + kid: KID, + alg: SigningAlgo.ES256K, + }), + payload: { + client_id: WELL_KNOWN_OPENID_FEDERATION, + scope: 'test', + response_type: 'vp_token', + redirect_uri: EXAMPLE_REDIRECT_URL, + request_object_signing_alg_values_supported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + claims: { + vp_token: { + dcql_query: JSON.stringify(dcqlQuery) + }, + }, + }, + }, + clientMetadata: { + client_id: WELL_KNOWN_OPENID_FEDERATION, + idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + responseTypesSupported: [ResponseType.ID_TOKEN], + scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], + subject_syntax_types_supported: ['did:ethr:', SubjectIdentifierType.DID], + subjectTypesSupported: [SubjectType.PAIRWISE], + vpFormatsSupported: { + ldp_vc: { + proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019], + }, + }, + + passBy: PassBy.VALUE, + + logo_uri: VERIFIER_LOGO_FOR_CLIENT, + clientName: VERIFIER_NAME_FOR_CLIENT, + 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100305', + clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, + 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, + }, + } + + const uriRequest = await URI.fromOpts(opts) + + const uriDecoded = decodeURIComponent(uriRequest.encodedUri) + expect(uriDecoded.startsWith('openid4vp://?')).toBeTruthy() + expect(uriDecoded).toContain(`request_uri=https://rp.acme.com/siop/jwts`) + expect((await (await uriRequest.toAuthorizationRequest())?.requestObject?.getPayload())?.claims.vp_token).toBeDefined() + }) }) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index 779480d3..b6908aad 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -8,6 +8,13 @@ import { IVerifiablePresentation, OriginalVerifiableCredential, } from '@sphereon/ssi-types' +import { + DcqlCredentialRepresentation, + DcqlPresentationRecord, + DcqlQuery, + DcqlQueryResult +} from 'dcql' +import { Json } from 'dcql/dist/src/u-dcql' import { AuthorizationResponse, @@ -650,4 +657,149 @@ describe('create JWT from Request JWT should', () => { const authResponse = AuthorizationResponse.fromRequestObject(jwt, responseOpts, verifyOpts) await expect(authResponse).toBeDefined() }) + + it('succeed when valid JWT with DCQL query is passed in', async () => { + expect.assertions(1) + + const mockReqEntity = await mockedGetEnterpriseAuthToken('REQ COMPANY') + const mockResEntity = await mockedGetEnterpriseAuthToken('RES COMPANY') + + const dcqlQuery: DcqlQuery = { + credentials: [ + { + id: 'Credentials', + format: 'jwt_vc_json-ld', + claims: [ + { + id: 'ID_Card_Credential', + path: ['$.issuer.id'], + values: ['did:example:issuer'], + }, + ], + }, + ], + } + + const dcqlParsedQuery = DcqlQuery.parse(dcqlQuery) + DcqlQuery.validate(dcqlParsedQuery) + + const requestOpts: CreateAuthorizationRequestOpts = { + version: SupportedVersion.SIOPv2_ID1, + requestObject: { + passBy: PassBy.REFERENCE, + reference_uri: 'https://my-request.com/here', + jwtIssuer: { method: 'did', didUrl: mockReqEntity.did, alg: SigningAlgo.ES256K }, + createJwtCallback: getCreateJwtCallback({ + hexPrivateKey: mockReqEntity.hexPrivateKey, + did: mockReqEntity.did, + kid: `${mockReqEntity.did}#controller`, + alg: SigningAlgo.ES256K, + }), + payload: { + client_id: WELL_KNOWN_OPENID_FEDERATION, + scope: 'test', + response_type: 'id_token vp_token', + redirect_uri: EXAMPLE_REDIRECT_URL, + claims: { + vp_token: { + dcql_query: dcqlParsedQuery, + }, + }, + }, + }, + clientMetadata: { + client_id: WELL_KNOWN_OPENID_FEDERATION, + idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + subject_syntax_types_supported: ['did:ethr:', SubjectIdentifierType.DID], + requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + responseTypesSupported: [ResponseType.ID_TOKEN], + scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], + subjectTypesSupported: [SubjectType.PAIRWISE], + vpFormatsSupported: { + ldp_vc: { + proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019], + }, + }, + passBy: PassBy.VALUE, + logo_uri: VERIFIER_LOGO_FOR_CLIENT, + clientName: VERIFIER_NAME_FOR_CLIENT, + 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100315', + clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, + 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, + }, + } + + const vc: DcqlCredentialRepresentation = { + docType: 'jsonld', + claims: { + id: 'https://example.com/credentials/1872', + type: ['VerifiableCredential', 'IDCardCredential'], + '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1/IDCardCredential'], + issuer: { + id: 'did:example:issuer', + }, + issuanceDate: '2010-01-01T19:23:24Z', + credentialSubject: { + given_name: 'Fredrik', + family_name: 'Stremberg', + birthdate: '1949-01-22', + }, + }, + } + + const dcqlQueryResult: DcqlQueryResult = DcqlQuery.query(dcqlQuery, [vc]) + + const presentation: DcqlPresentationRecord.Output = {} + for (const [key, value] of Object.entries(dcqlQueryResult.credential_matches)) { + if (value.success) { + presentation[key] = value.output as string | { [x: string]: Json } + } + } + + const encodedPresentationRecord = DcqlPresentationRecord.parse(presentation) + + const responseOpts: AuthorizationResponseOpts = { + responseURI: EXAMPLE_REDIRECT_URL, + responseURIType: 'redirect_uri', + registration: { + authorizationEndpoint: 'www.myauthorizationendpoint.com', + issuer: ResponseIss.SELF_ISSUED_V2, + responseTypesSupported: [ResponseType.ID_TOKEN], + passBy: PassBy.REFERENCE, + reference_uri: EXAMPLE_REFERENCE_URL, + + subject_syntax_types_supported: ['did:ethr:', SubjectIdentifierType.DID], + vpFormats: { + ldp_vc: { + proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019], + }, + }, + logo_uri: VERIFIER_LOGO_FOR_CLIENT, + clientName: VERIFIER_NAME_FOR_CLIENT, + 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100316', + clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, + 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, + }, + createJwtCallback: getCreateJwtCallback({ + did: mockResEntity.did, + hexPrivateKey: mockResEntity.hexPrivateKey, + kid: `${mockResEntity.did}#controller`, + alg: SigningAlgo.ES256K, + }), + jwtIssuer: { method: 'did', didUrl: `${mockResEntity.did}#controller`, alg: SigningAlgo.ES256K }, + dcqlQuery: { + encodedPresentationRecord + }, + responseMode: ResponseMode.POST, + } + + const requestObject = await RequestObject.fromOpts(requestOpts) + /* console.log( + JSON.stringify(await AuthenticationResponse.createJWTFromRequestJWT(requestWithJWT.jwt, responseOpts, verifyOpts)) + );*/ + const jwt = await requestObject.toJwt() + if (!jwt) throw new Error('JWT is undefined') + const authorizationRequest = await AuthorizationResponse.fromRequestObject(jwt, responseOpts, verifyOpts) + expect(authorizationRequest).toBeDefined() + }) }) From f94344e427494c9c50c7183c7de0c420ac19cc81 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Wed, 18 Dec 2024 15:06:32 +0100 Subject: [PATCH 20/48] chore: "fixed succeed when valid JWT with DCQL query is passed in" to pass in a SIOPv2_D12_OID4VP_D20 version request --- .../AuthenticationResponse.response.spec.ts | 29 ++----------------- packages/siop-oid4vp/lib/id-token/IDToken.ts | 2 +- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index b6908aad..dea1906d 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -684,7 +684,7 @@ describe('create JWT from Request JWT should', () => { DcqlQuery.validate(dcqlParsedQuery) const requestOpts: CreateAuthorizationRequestOpts = { - version: SupportedVersion.SIOPv2_ID1, + version: SupportedVersion.SIOPv2_D12_OID4VP_D20, requestObject: { passBy: PassBy.REFERENCE, reference_uri: 'https://my-request.com/here', @@ -700,11 +700,7 @@ describe('create JWT from Request JWT should', () => { scope: 'test', response_type: 'id_token vp_token', redirect_uri: EXAMPLE_REDIRECT_URL, - claims: { - vp_token: { - dcql_query: dcqlParsedQuery, - }, - }, + dcql_query: JSON.stringify(dcqlParsedQuery), }, }, clientMetadata: { @@ -761,25 +757,6 @@ describe('create JWT from Request JWT should', () => { const responseOpts: AuthorizationResponseOpts = { responseURI: EXAMPLE_REDIRECT_URL, responseURIType: 'redirect_uri', - registration: { - authorizationEndpoint: 'www.myauthorizationendpoint.com', - issuer: ResponseIss.SELF_ISSUED_V2, - responseTypesSupported: [ResponseType.ID_TOKEN], - passBy: PassBy.REFERENCE, - reference_uri: EXAMPLE_REFERENCE_URL, - - subject_syntax_types_supported: ['did:ethr:', SubjectIdentifierType.DID], - vpFormats: { - ldp_vc: { - proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019], - }, - }, - logo_uri: VERIFIER_LOGO_FOR_CLIENT, - clientName: VERIFIER_NAME_FOR_CLIENT, - 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100316', - clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, - 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, - }, createJwtCallback: getCreateJwtCallback({ did: mockResEntity.did, hexPrivateKey: mockResEntity.hexPrivateKey, @@ -790,7 +767,7 @@ describe('create JWT from Request JWT should', () => { dcqlQuery: { encodedPresentationRecord }, - responseMode: ResponseMode.POST, + responseMode: ResponseMode.DIRECT_POST, } const requestObject = await RequestObject.fromOpts(requestOpts) diff --git a/packages/siop-oid4vp/lib/id-token/IDToken.ts b/packages/siop-oid4vp/lib/id-token/IDToken.ts index ac142218..d94d36bb 100644 --- a/packages/siop-oid4vp/lib/id-token/IDToken.ts +++ b/packages/siop-oid4vp/lib/id-token/IDToken.ts @@ -99,7 +99,7 @@ export class IDToken { const did = jwtIssuer.didUrl.split('#')[0] this._payload.sub = did - const issuer = this._responseOpts.registration.issuer || this._payload.iss + const issuer = this._responseOpts.registration?.issuer || this._payload.iss if (!issuer || !(issuer.includes(ResponseIss.SELF_ISSUED_V2) || issuer === this._payload.sub)) { throw new Error(SIOPErrors.NO_SELF_ISSUED_ISS) } From 7e0c198c38f611760ea272ec498eb1163965f922 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 18 Dec 2024 17:47:52 +0100 Subject: [PATCH 21/48] Fix: Added the hasher and compact sdjwt credential to the AuthorizationRequest --- .../AuthenticationResponse.response.spec.ts | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index dea1906d..a82a730e 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -8,13 +8,7 @@ import { IVerifiablePresentation, OriginalVerifiableCredential, } from '@sphereon/ssi-types' -import { - DcqlCredentialRepresentation, - DcqlPresentationRecord, - DcqlQuery, - DcqlQueryResult -} from 'dcql' -import { Json } from 'dcql/dist/src/u-dcql' +import { DcqlCredentialRepresentation, DcqlPresentationRecord, DcqlQuery, DcqlQueryResult } from 'dcql' import { AuthorizationResponse, @@ -39,7 +33,7 @@ import SIOPErrors from '../types/Errors' import { getCreateJwtCallback, getVerifyJwtCallback } from './DidJwtTestUtils' import { getResolver } from './ResolverTestUtils' -import { mockedGetEnterpriseAuthToken, WELL_KNOWN_OPENID_FEDERATION } from './TestUtils' +import { mockedGetEnterpriseAuthToken, pexHasher, WELL_KNOWN_OPENID_FEDERATION } from './TestUtils' import { UNIT_TEST_TIMEOUT, VERIFIER_LOGO_FOR_CLIENT, @@ -97,6 +91,7 @@ describe('create JWT from Request JWT should', () => { const resolver = getResolver('ethr') const verifyOpts: VerifyAuthorizationRequestOpts = { + hasher: pexHasher, verifyJwtCallback: getVerifyJwtCallback(resolver), verification: {}, supportedVersions: [SupportedVersion.SIOPv2_ID1], @@ -668,12 +663,11 @@ describe('create JWT from Request JWT should', () => { credentials: [ { id: 'Credentials', - format: 'jwt_vc_json-ld', + format: 'vc+sd-jwt', claims: [ { - id: 'ID_Card_Credential', - path: ['$.issuer.id'], - values: ['did:example:issuer'], + path: ['given_name'], + values: ['John'], }, ], }, @@ -725,30 +719,47 @@ describe('create JWT from Request JWT should', () => { }, } - const vc: DcqlCredentialRepresentation = { - docType: 'jsonld', - claims: { - id: 'https://example.com/credentials/1872', - type: ['VerifiableCredential', 'IDCardCredential'], - '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1/IDCardCredential'], - issuer: { - id: 'did:example:issuer', + const sdjwt = { + compactJwtVc: + 'eyJ0eXAiOiJ2YytzZC1qd3QiLCJraWQiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW5WelpTSTZJbk5wWnlJc0ltdDBlU0k2SWtWRElpd2lZM0oySWpvaVVDMHlOVFlpTENKNElqb2lTMGRwYzNodlUzaDJhVzB4YTFOSU1XSnROMnhmUkhCeVIyczNZa2RrWkVaYVdXWnRjVXB1VjJWb1NTSXNJbmtpT2lKYVEzQldUVVZSTkhsNGNUSlZiVGRDVGpoSVQyNUdlamszTTFBMFVUQlVkbmRuZVhWUlgyRmlURlZWSW4wIzAiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW5WelpTSTZJbk5wWnlJc0ltdDBlU0k2SWtWRElpd2lZM0oySWpvaVVDMHlOVFlpTENKNElqb2lXRkpXUVhsNVJIQldNbXBNTm5oNlUwSktZM1JIZW0xS1pqbFFlV0Z4WHpNdFRVeHJlR0ZoUlRBNFRTSXNJbmtpT2lKQ1NtOUtWM05WYTBaQlUyVlRZMmx4VDFsNVNWTTBZMFpoZVU4emFHaEJTalZaYjJ0dU9IcFRTVEZuSW4wIzAiLCJpc3MiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW5WelpTSTZJbk5wWnlJc0ltdDBlU0k2SWtWRElpd2lZM0oySWpvaVVDMHlOVFlpTENKNElqb2lTMGRwYzNodlUzaDJhVzB4YTFOSU1XSnROMnhmUkhCeVIyczNZa2RrWkVaYVdXWnRjVXB1VjJWb1NTSXNJbmtpT2lKYVEzQldUVVZSTkhsNGNUSlZiVGRDVGpoSVQyNUdlamszTTFBMFVUQlVkbmRuZVhWUlgyRmlURlZWSW4wIzAiLCJpYXQiOjE3MzQ0NTgwNDIsInZjdCI6InVybjpldS5ldXJvcGEuZWMuZXVkaTpwaWQ6MSIsIl9zZCI6WyIwWWdpR25hck1LSERnVWx1QktteGdRZUJ4OF8xazMwd3NSRVN1X2t1Y0JFIiwiNEpwU2JzUEsxZndUQzRhR24zZ0hXb1BkVEJrMExOTWZMOEJXeEIxZ1JPWSIsIjRpZmplQUZveUEyQmc0STVNWEFrMVlyc1AtUVBQQXRnZGlHY0RMQTZiTFEiLCJBdTFjdURISUNISE1jUjZxM2R3d1pHbHp5dzMwSXhvTGVhWlNxRktEbmo4IiwiQ0QxbWxOY19VaVBoQUp6YkJveTVMY3dtekFNZTM3d0VLZF9iMTB6QTNxNCIsInFwZ1FOUVRac0VJWHdxUk9fT24xdUVCSVVNODBTcTJLR2tlN0JSU2N0WHciXSwiX3NkX2FsZyI6IlNIQS0yNTYifQ.P84d0CoS4M-zQ29l3S97RMatfJMYkoTgR5EqSMTdYlZAMp4e8iiuz2PXQMfJ-_undCvg4SRXxDACGiLL3Tt7Bw~WyJlNTFiNWI2NS0wNzM3LTQ0MjQtYTUxYS1jNGYzZGNlZGFmMmYiLCJnaXZlbl9uYW1lIiwiSm9obiJd~WyIxM2I1NDIwNi1kYWQ3LTQ3N2UtODYyZC03N2ZiMTQ1MDE5NjUiLCJmYW1pbHlfbmFtZSIsIkRvZSJd~WyJkMmQxNjg3Zi04ZmY4LTRlOTMtYWJjYi1hYTNlNGVjYzY0ZTMiLCJlbWFpbCIsImpvaG5kZW9AZXhhbXBsZS5jb20iXQ~WyIyZDA4YTk2YS03YzYwLTQ3NDEtYTI5YS00ZjBjYTFlNGQ3M2IiLCJwaG9uZSIsIisxLTIwMi01NTUtMDEwMSJd~WyI2YjVkN2FmOS01ZmIxLTQzNTEtYWM1ZS1hMzA1YTBkNjU0ZDUiLCJhZGRyZXNzIix7InN0cmVldF9hZGRyZXNzIjoiMTIzIE1haW4gU3QiLCJsb2NhbGl0eSI6IkFueXRvd24iLCJyZWdpb24iOiJBbnlzdGF0ZSIsImNvdW50cnkiOiJVUyJ9XQ~WyI5MmYzY2M5ZC0yMjQ2LTRiODQtYTk5OS0xYmQyM2U0OGQ0MGEiLCJiaXJ0aGRhdGUiLCIxOTQwLTAxLTAxIl0~', + decodedPayload: { + header: { + typ: 'vc+sd-jwt', + kid: 'did:jwk:eyJhbGciOiJFUzI1NiIsInVzZSI6InNpZyIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiS0dpc3hvU3h2aW0xa1NIMWJtN2xfRHByR2s3YkdkZEZaWWZtcUpuV2VoSSIsInkiOiJaQ3BWTUVRNHl4cTJVbTdCTjhIT25Gejk3M1A0UTBUdndneXVRX2FiTFVVIn0#0', + alg: 'ES256', }, - issuanceDate: '2010-01-01T19:23:24Z', - credentialSubject: { - given_name: 'Fredrik', - family_name: 'Stremberg', - birthdate: '1949-01-22', + payload: { + sub: 'did:jwk:eyJhbGciOiJFUzI1NiIsInVzZSI6InNpZyIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiWFJWQXl5RHBWMmpMNnh6U0JKY3RHem1KZjlQeWFxXzMtTUxreGFhRTA4TSIsInkiOiJCSm9KV3NVa0ZBU2VTY2lxT1l5SVM0Y0ZheU8zaGhBSjVZb2tuOHpTSTFnIn0#0', + iss: 'did:jwk:eyJhbGciOiJFUzI1NiIsInVzZSI6InNpZyIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiS0dpc3hvU3h2aW0xa1NIMWJtN2xfRHByR2s3YkdkZEZaWWZtcUpuV2VoSSIsInkiOiJaQ3BWTUVRNHl4cTJVbTdCTjhIT25Gejk3M1A0UTBUdndneXVRX2FiTFVVIn0#0', + iat: 1734458042, + vct: 'urn:eu.europa.ec.eudi:pid:1', + given_name: 'John', + email: 'johndeo@example.com', + birthdate: '1940-01-01', + phone: '+1-202-555-0101', + address: { + street_address: '123 Main St', + locality: 'Anytown', + region: 'Anystate', + country: 'US', + }, + family_name: 'Doe', }, + kb: undefined, }, } + const vc: DcqlCredentialRepresentation = { + vct: sdjwt.decodedPayload.payload.vct, + claims: sdjwt.decodedPayload.payload, + } + const dcqlQueryResult: DcqlQueryResult = DcqlQuery.query(dcqlQuery, [vc]) const presentation: DcqlPresentationRecord.Output = {} for (const [key, value] of Object.entries(dcqlQueryResult.credential_matches)) { if (value.success) { - presentation[key] = value.output as string | { [x: string]: Json } + presentation[key] = sdjwt.compactJwtVc } } @@ -765,7 +776,7 @@ describe('create JWT from Request JWT should', () => { }), jwtIssuer: { method: 'did', didUrl: `${mockResEntity.did}#controller`, alg: SigningAlgo.ES256K }, dcqlQuery: { - encodedPresentationRecord + encodedPresentationRecord, }, responseMode: ResponseMode.DIRECT_POST, } From 169118cd8b87bf784714e2639f208b38b1a4767c Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Mon, 30 Dec 2024 13:50:11 +0100 Subject: [PATCH 22/48] Fix: Fixed broken IT tests --- packages/siop-oid4vp/lib/__tests__/IT.spec.ts | 4 ++-- packages/siop-oid4vp/lib/rp/RP.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/IT.spec.ts b/packages/siop-oid4vp/lib/__tests__/IT.spec.ts index 11ff6795..8bb15898 100644 --- a/packages/siop-oid4vp/lib/__tests__/IT.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/IT.spec.ts @@ -141,7 +141,7 @@ function getVCs(): IVerifiableCredential[] { return vcs } -describe.skip('RP and OP interaction should', () => { +describe('RP and OP interaction should', () => { // FIXME SDK-45 Uniresolver failing it( 'succeed when calling each other in the full flow', @@ -425,7 +425,7 @@ describe.skip('RP and OP interaction should', () => { const verifiedAuthReqWithJWT = await op.verifyAuthorizationRequest(parsedAuthReqURI.requestObjectJwt) expect(verifiedAuthReqWithJWT.issuer).toMatch(rpMockEntity.did) await expect(op.createAuthorizationResponse(verifiedAuthReqWithJWT, {})).rejects.toThrow( - Error('authentication request expects a verifiable presentation in the response'), + Error('vp_token is present, but no presentation definitions or dcql query provided'), ) expect(verifiedAuthReqWithJWT.payload?.['registration'].client_name).toEqual(VERIFIER_NAME_FOR_CLIENT) diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index 52981b78..be7fc1fb 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -425,10 +425,10 @@ export class RP { nonce, verification: mergeVerificationOpts(this._verifyResponseOptions, opts), ...(opts?.presentationDefinitions && !opts?.dcqlQuery && { - presentationDefinitions: this._verifyResponseOptions.presentationDefinitions + presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions }), - ...(opts?.dcqlQuery && { - dcqlQuery: this._verifyResponseOptions.dcqlQuery + ...(opts?.dcqlQuery && !opts?.presentationDefinitions && { + dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery }) } } From 3cc42b15d50e87ce5dd7b839199c840a2fcaed30 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Mon, 30 Dec 2024 14:12:48 +0100 Subject: [PATCH 23/48] Fix: Removed skip from tests that are running successfully --- packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index a5e63522..059c20d5 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -84,7 +84,7 @@ function getVCs(): OriginalVerifiableCredential[] { return [SD_JWT_VC] } -describe.skip('RP and OP interaction should', () => { +describe('RP and OP interaction should', () => { // FIXME SDK-45 Uniresolver failing it('succeed when calling with presentation definitions and right verifiable presentation', async () => { const opMock = await mockedGetEnterpriseAuthToken('OP') From 88ce80cfb3d44b3605761f95440128984e813201 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 31 Dec 2024 14:03:49 +0100 Subject: [PATCH 24/48] chore: added DCQL tests --- .../siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 137 +++++++++++++++++- .../AuthorizationRequest.ts | 2 +- .../lib/helpers/SIOPSpecVersion.ts | 2 +- 3 files changed, 137 insertions(+), 4 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index 059c20d5..c6fbda06 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -1,6 +1,8 @@ -import { SigningAlgo } from '@sphereon/oid4vc-common' +import { defaultHasher, SigningAlgo } from '@sphereon/oid4vc-common' import { IPresentationDefinition } from '@sphereon/pex' -import { OriginalVerifiableCredential } from '@sphereon/ssi-types' +import { decodeSdJwtVc, OriginalVerifiableCredential } from '@sphereon/ssi-types' +import { DcqlCredentialRepresentation, DcqlQuery } from 'dcql' +import { Json } from 'dcql/dist/src/u-dcql' import { OP, @@ -10,6 +12,7 @@ import { PresentationVerificationCallback, PropertyTarget, ResponseIss, + ResponseMode, ResponseType, RevocationVerification, RP, @@ -80,6 +83,21 @@ function getPresentationDefinition(): IPresentationDefinition { } } +const sdJwtVcQuery: DcqlQuery = { + credentials: [ + { + id: 'my_credential', + format: 'vc+sd-jwt', + meta: { + vct_values: ['https://high-assurance.com/StateBusinessLicense'], + }, + claims: [{ path: ['license', 'number'] }, { path: ['user', 'name'] }], + }, + ], +} + +DcqlQuery.validate(sdJwtVcQuery) + function getVCs(): OriginalVerifiableCredential[] { return [SD_JWT_VC] } @@ -326,4 +344,119 @@ describe('RP and OP interaction should', () => { expect(verifiedAuthResponseWithJWT.oid4vpSubmission?.nonce).toEqual('qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg') expect(verifiedAuthResponseWithJWT.idToken).toBeUndefined() }) + + it('succeed when calling with DCQL and right verifiable presentation', async () => { + const opMock = await mockedGetEnterpriseAuthToken('OP') + const opMockEntity = { + ...opMock, + didKey: `${opMock.did}#controller`, + } + const rpMock = await mockedGetEnterpriseAuthToken('RP') + const rpMockEntity = { + ...rpMock, + didKey: `${rpMock.did}#controller`, + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const presentationVerificationCallback: PresentationVerificationCallback = async (_args) => { + return { verified: true } + } + + const resolver = getResolver('ethr') + const rp = RP.builder({ requestVersion: SupportedVersion.SIOPv2_D12_OID4VP_D20 }) + .withClientId(rpMockEntity.did) + .withScope('test') + .withHasher(pexHasher) + .withResponseType([ResponseType.ID_TOKEN, ResponseType.VP_TOKEN]) + .withResponseMode(ResponseMode.DIRECT_POST) + .withRedirectUri(EXAMPLE_REDIRECT_URL) + .withDcqlQuery(JSON.stringify(sdJwtVcQuery), [PropertyTarget.REQUEST_OBJECT]) + .withPresentationVerification(presentationVerificationCallback) + .withRevocationVerification(RevocationVerification.NEVER) + .withRequestBy(PassBy.VALUE) + .withCreateJwtCallback(internalSignature(rpMockEntity.hexPrivateKey, rpMockEntity.did, `${rpMockEntity.did}#controller`, SigningAlgo.ES256K)) + .withAuthorizationEndpoint('www.myauthorizationendpoint.com') + .withVerifyJwtCallback(getVerifyJwtCallback(resolver)) + .withClientMetadata({ + client_id: WELL_KNOWN_OPENID_FEDERATION, + idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA], + requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + responseTypesSupported: [ResponseType.ID_TOKEN], + vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA] } }, + scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], + subjectTypesSupported: [SubjectType.PAIRWISE], + subject_syntax_types_supported: ['did', 'did:key'], + passBy: PassBy.VALUE, + logo_uri: VERIFIER_LOGO_FOR_CLIENT, + clientName: VERIFIER_NAME_FOR_CLIENT, + 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100322', + clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, + 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, + }) + .build() + + const op = OP.builder() + .withPresentationSignCallback(sdJwtVcPresentationSignCallback) + .withExpiresIn(1000) + .withHasher(pexHasher) + .withCreateJwtCallback(internalSignature(opMockEntity.hexPrivateKey, opMockEntity.did, `${opMockEntity.did}#controller`, SigningAlgo.ES256K)) + .withVerifyJwtCallback(getVerifyJwtCallback(resolver)) + .withRegistration({ + authorizationEndpoint: 'www.myauthorizationendpoint.com', + idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA], + issuer: ResponseIss.SELF_ISSUED_V2, + requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], + responseTypesSupported: [ResponseType.ID_TOKEN, ResponseType.VP_TOKEN], + vpFormats: { jwt_vc: { alg: [SigningAlgo.EDDSA] } }, + scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], + subjectTypesSupported: [SubjectType.PAIRWISE], + subject_syntax_types_supported: [], + passBy: PassBy.VALUE, + logo_uri: VERIFIER_LOGO_FOR_CLIENT, + clientName: VERIFIER_NAME_FOR_CLIENT, + 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100323', + clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, + 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, + }) + .withSupportedVersions(SupportedVersion.SIOPv2_D12_OID4VP_D20) + .build() + + const requestURI = await rp.createAuthorizationRequestURI({ + correlationId: '1234', + nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', + state: 'b32f0087fc9816eb813fd11f', + }) + + // Let's test the parsing + const parsedAuthReqURI = await op.parseAuthorizationRequestURI(requestURI.encodedUri) + expect(parsedAuthReqURI.authorizationRequestPayload).toBeDefined() + expect(parsedAuthReqURI.requestObjectJwt).toBeDefined() + + if (!parsedAuthReqURI.requestObjectJwt) throw new Error('requestObjectJwt is undefined') + const verifiedAuthReqWithJWT = await op.verifyAuthorizationRequest(parsedAuthReqURI.requestObjectJwt) + expect(verifiedAuthReqWithJWT.issuer).toMatch(rpMockEntity.did) + + const dcqlCredentials: DcqlCredentialRepresentation[] = getVCs().map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json } })) + + const queryResult = DcqlQuery.query(sdJwtVcQuery, dcqlCredentials) + + const encodedPresentationRecord: { [x: string]: string | { [x: string]: Json } } = {} + + for (const [key, _] of Object.entries(queryResult.credential_matches)) { + encodedPresentationRecord[key] = getVCs()[0] as string | { [x: string]: Json } + } + + const authenticationResponseWithJWT = await op.createAuthorizationResponse(verifiedAuthReqWithJWT, { + dcqlQuery: { encodedPresentationRecord }, + }) + expect(authenticationResponseWithJWT.response.payload).toBeDefined() + expect(authenticationResponseWithJWT.response.idToken).toBeDefined() + + const verifiedAuthResponseWithJWT = await rp.verifyAuthorizationResponse(authenticationResponseWithJWT.response.payload, { + dcqlQuery: sdJwtVcQuery, + }) + + expect(verifiedAuthResponseWithJWT.idToken?.jwt).toBeDefined() + expect(verifiedAuthResponseWithJWT.idToken?.payload.nonce).toMatch('qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg') + }) }) diff --git a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts index aeb4b15b..dc6bc93e 100644 --- a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts +++ b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts @@ -2,7 +2,7 @@ import { parseJWT } from '@sphereon/oid4vc-common' import { DcqlQuery } from 'dcql' import { PresentationDefinitionWithLocation } from '../authorization-response' -import { findValidDcqlQuery } from '../authorization-response/Dcql' +import { findValidDcqlQuery } from '../authorization-response' import { PresentationExchange } from '../authorization-response/PresentationExchange' import { fetchByReferenceOrUseByValue, removeNullUndefined } from '../helpers' import { authorizationRequestVersionDiscovery } from '../helpers/SIOPSpecVersion' diff --git a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts index 5e41e4e8..8efa2b9a 100644 --- a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts +++ b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts @@ -44,7 +44,7 @@ export const authorizationRequestVersionDiscovery = (authorizationRequest: Autho !authorizationRequestCopy.registration_uri && !authorizationRequestCopy.registration && !(authorizationRequestCopy.claims && 'vp_token' in authorizationRequestCopy.claims) && - authorizationRequestCopy.response_mode !== ResponseMode.POST // Post has been replaced by direct post + authorizationRequestCopy.response_mode !== ResponseMode.DIRECT_POST // Post has been replaced by direct post ) { versions.push(SupportedVersion.SIOPv2_D12_OID4VP_D20) } From e5a1854908dcbcc0744c54834897f35e615c1845 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Thu, 2 Jan 2025 18:11:34 +0100 Subject: [PATCH 25/48] Fix: Nonce was searched in the wrong place --- packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 6 ++++-- .../siop-oid4vp/lib/authorization-response/OpenID4VP.ts | 7 +------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index c6fbda06..c84a67af 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -40,6 +40,7 @@ const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const HOLDER_DID = 'did:example:ebfeb1f712ebc6f1c276e12ec21' const SD_JWT_VC = 'eyJhbGciOiJFZERTQSIsInR5cCI6InZjK3NkLWp3dCJ9.eyJpYXQiOjE3MDA0NjQ3MzYwNzYsImlzcyI6ImRpZDprZXk6c29tZS1yYW5kb20tZGlkLWtleSIsIm5iZiI6MTcwMDQ2NDczNjE3NiwidmN0IjoiaHR0cHM6Ly9oaWdoLWFzc3VyYW5jZS5jb20vU3RhdGVCdXNpbmVzc0xpY2Vuc2UiLCJ1c2VyIjp7Il9zZCI6WyI5QmhOVDVsSG5QVmpqQUp3TnR0NDIzM216MFVVMUd3RmFmLWVNWkFQV0JNIiwiSVl5d1FQZl8tNE9hY2Z2S2l1cjRlSnFMa1ZleWRxcnQ1Y2UwMGJReWNNZyIsIlNoZWM2TUNLakIxeHlCVl91QUtvLURlS3ZvQllYbUdBd2VGTWFsd05xbUEiLCJXTXpiR3BZYmhZMkdoNU9pWTRHc2hRU1dQREtSeGVPZndaNEhaQW5YS1RZIiwiajZ6ZFg1OUJYZHlTNFFaTGJITWJ0MzJpenRzWXdkZzRjNkpzWUxNc3ZaMCIsInhKR3Radm41cFM4VEhqVFlJZ3MwS1N5VC1uR3BSR3hDVnp6c1ZEbmMyWkUiXX0sImxpY2Vuc2UiOnsibnVtYmVyIjoxMH0sImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwieSI6Ilp4amlXV2JaTVFHSFZXS1ZRNGhiU0lpcnNWZnVlY0NFNnQ0alQ5RjJIWlEifX0sIl9zZF9hbGciOiJzaGEtMjU2IiwiX3NkIjpbIl90YnpMeHBaeDBQVHVzV2hPOHRUZlVYU2ZzQjVlLUtrbzl3dmZaaFJrYVkiLCJ1WmNQaHdUTmN4LXpNQU1zemlYMkFfOXlJTGpQSEhobDhEd2pvVXJLVVdZIl19.HAcudVInhNpXkTPQGNosjKTFRJWgKj90NpfloRaDQchGd4zxc1ChWTCCPXzUXTBypASKrzgjZCiXlTr0bzmLAg~WyJHeDZHRUZvR2t6WUpWLVNRMWlDREdBIiwiZGF0ZU9mQmlydGgiLCIyMDAwMDEwMSJd~WyJ1LUt3cmJvMkZfTExQekdSZE1XLUtBIiwibmFtZSIsIkpvaG4iXQ~WyJNV1ZieGJqVFZxUXdLS3h2UGVZdWlnIiwibGFzdE5hbWUiLCJEb2UiXQ~' +const KB_SD_JWT_PRESENTATION = 'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6a2V5OnNvbWUtcmFuZG9tLWRpZC1rZXkiLCJpYXQiOjE3MzU4MzY0NzY1NjksInZjdCI6Imh0dHBzOi8vaGlnaC1hc3N1cmFuY2UuY29tL1N0YXRlQnVzaW5lc3NMaWNlbnNlIiwiX3NkIjpbIk5ub3U2OGN6VG9qQWY0Z3dIMmJiNFBaWHB4WHJzQ29oWm5CbEZvQ293TTAiLCJ1ajZZZVZwSnRwUjhVWHRpbmVDOGM5LXpTRFJVQzJzSGhsRkNNNWtkLXlNIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.X1pNBBmR-7h6SgxtmZY9GL_nSBzoIvWNw7nqqgJVCnSEbvyTjqTgu4bLSPKeaxf1jY2zHJK1jdxiDzIizRZ0gA~WyI4OTE4YjkxZGFjMzk1OTdkIiwidXNlciIseyJkYXRlX29mX2JpcnRoIjoiMDEvMDEvMTk3MCIsIl9zZCI6WyJ6UE8zb1RCT3BxMmRNcWQtekt5SmF2UlQyWVIwSHBPaV9jczZRajEtVmR3Il19XQ~WyIyOTc4NTNiODE5MTI0MTJkIiwibmFtZSIsIkpvaG4iXQ~WyJkYjEzNDQ4NTgxMzY0M2JlIiwibGljZW5zZSIseyJfc2QiOlsiWUFUR3A3TGxjNEMtTWtYWkZWTEF6RHRtbDFTMVpFWFFyTW5CdmVDWVFwayJdfV0~WyJlOTc3MzhiNmM0OGNhMWJlIiwibnVtYmVyIiwxMF0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE3MzU4MzY0NzYsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJub25jZSI6InFCclI3bXFuWTNRcjQ5ZEFaeWNQRjhGemdFODNtNkgwYzJsMGJ6UDR4U2ciLCJjdXN0b20iOiJkYXRhIiwic2RfaGFzaCI6IlVwYzNYQWpzRU1mdnVmSzJ5Q3RkNDZXUFJmTDVfVDc4UThEZVNZQXlEX28ifQ.Crw56nLFFnVulRQElpq9HoskdKIyd5Mj6vg9UVNSWfhxQ0oGe10RHtifUv4BiFharSvWN99y_DnkhCPu1sPIYw' function getPresentationDefinition(): IPresentationDefinition { return { @@ -436,14 +437,15 @@ describe('RP and OP interaction should', () => { const verifiedAuthReqWithJWT = await op.verifyAuthorizationRequest(parsedAuthReqURI.requestObjectJwt) expect(verifiedAuthReqWithJWT.issuer).toMatch(rpMockEntity.did) - const dcqlCredentials: DcqlCredentialRepresentation[] = getVCs().map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json } })) + // FIXME kb-sd-jwts are not working with pex, so the presentation was not added to getVCs(...) + const dcqlCredentials: DcqlCredentialRepresentation[] = [KB_SD_JWT_PRESENTATION].map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json } })) const queryResult = DcqlQuery.query(sdJwtVcQuery, dcqlCredentials) const encodedPresentationRecord: { [x: string]: string | { [x: string]: Json } } = {} for (const [key, _] of Object.entries(queryResult.credential_matches)) { - encodedPresentationRecord[key] = getVCs()[0] as string | { [x: string]: Json } + encodedPresentationRecord[key] = KB_SD_JWT_PRESENTATION as string | { [x: string]: Json } } const authenticationResponseWithJWT = await op.createAuthorizationResponse(verifiedAuthReqWithJWT, { diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 38cd6e8f..e290ca24 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -1,4 +1,3 @@ -import { parseJWT } from '@sphereon/oid4vc-common' import { IPresentationDefinition, PEX, PresentationSubmissionLocation } from '@sphereon/pex' import { Format } from '@sphereon/pex-models' import { @@ -43,11 +42,7 @@ export const extractNonceFromWrappedVerifiablePresentation = (wrappedVp: Wrapped // TODO: replace this once `kbJwt.payload` is available on the decoded sd-jwt (pr in ssi-sdk) // If it doesn't end with ~, it contains a kbJwt if (!wrappedVp.presentation.compactSdJwtVc.endsWith('~')) { - const kbJwt = wrappedVp.presentation.compactSdJwtVc.split('~').pop() - - const { payload } = parseJWT(kbJwt) - - return payload.nonce + return wrappedVp.presentation.kbJwt.payload.nonce } // No kb-jwt means no nonce (error will be handled later) From 1c2838f6a8f925088ec91457be2e3f37e9b04ed1 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 3 Jan 2025 15:17:20 +0100 Subject: [PATCH 26/48] Fix: Fixed the SD-JWT sign callback and added extra DCQL test --- .../siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 71 ++++++++++++++++++- .../siop-oid4vp/lib/__tests__/TestUtils.ts | 61 +++++++++++++--- packages/siop-oid4vp/package.json | 3 + pnpm-lock.yaml | 46 ++++++++++++ 4 files changed, 168 insertions(+), 13 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index c84a67af..d2614c30 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -437,11 +437,78 @@ describe('RP and OP interaction should', () => { const verifiedAuthReqWithJWT = await op.verifyAuthorizationRequest(parsedAuthReqURI.requestObjectJwt) expect(verifiedAuthReqWithJWT.issuer).toMatch(rpMockEntity.did) - // FIXME kb-sd-jwts are not working with pex, so the presentation was not added to getVCs(...) - const dcqlCredentials: DcqlCredentialRepresentation[] = [KB_SD_JWT_PRESENTATION].map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json } })) + // The KB property is added to the JWT when the presentation is signed. Passing a VC will make the test fail + const dcqlCredentials: DcqlCredentialRepresentation[] = [KB_SD_JWT_PRESENTATION].map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json }, vct: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload.vct } )) const queryResult = DcqlQuery.query(sdJwtVcQuery, dcqlCredentials) + expect(queryResult).toEqual({ + "canBeSatisfied": true, + "credential_matches": { + "my_credential": { + "all": [ + [ + { + "credential_index": 0, + "output": { + "claims": { + "license": { + "number": 10 + }, + "user": { + "name": "John" + } + }, + "vct": "https://high-assurance.com/StateBusinessLicense" + }, + "success": true, + "typed": true + } + ] + ], + "credential_index": 0, + "output": { + "claims": { + "license": { + "number": 10 + }, + "user": { + "name": "John" + } + }, + "vct": "https://high-assurance.com/StateBusinessLicense" + }, + "success": true, + "typed": true + } + }, + "credentials": [ + { + "claims": [ + { + "path": [ + "license", + "number" + ] + }, + { + "path": [ + "user", + "name" + ] + } + ], + "format": "vc+sd-jwt", + "id": "my_credential", + "meta": { + "vct_values": [ + "https://high-assurance.com/StateBusinessLicense" + ] + } + } + ] + }) + const encodedPresentationRecord: { [x: string]: string | { [x: string]: Json } } = {} for (const [key, _] of Object.entries(queryResult.credential_matches)) { diff --git a/packages/siop-oid4vp/lib/__tests__/TestUtils.ts b/packages/siop-oid4vp/lib/__tests__/TestUtils.ts index bf073abe..33f30091 100644 --- a/packages/siop-oid4vp/lib/__tests__/TestUtils.ts +++ b/packages/siop-oid4vp/lib/__tests__/TestUtils.ts @@ -2,9 +2,11 @@ // @ts-ignore import crypto, { createHash } from 'crypto' +import { digest, ES256, generateSalt } from '@sd-jwt/crypto-nodejs' +import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc' import { JwtPayload, parseJWT, SigningAlgo, uuidv4 } from '@sphereon/oid4vc-common' import { PartialSdJwtDecodedVerifiableCredential } from '@sphereon/pex/dist/main/lib' -import { IProofType } from '@sphereon/ssi-types' +import { IProofType, SdJwtVcKbJwtPayload } from '@sphereon/ssi-types' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import base58 from 'bs58' @@ -26,7 +28,7 @@ import { RPRegistrationMetadataPayload, Scope, SubjectSyntaxTypesSupportedValues, - SubjectType, + SubjectType } from '../' import SIOPErrors from '../types/Errors' @@ -38,9 +40,10 @@ import { VERIFIER_NAME_FOR_CLIENT, VERIFIER_NAME_FOR_CLIENT_NL, VERIFIERZ_PURPOSE_TO_VERIFY, - VERIFIERZ_PURPOSE_TO_VERIFY_NL, + VERIFIERZ_PURPOSE_TO_VERIFY_NL } from './data/mockedData' + export interface TESTKEY { key: JWK did: string @@ -303,15 +306,51 @@ export const sdJwtVcPresentationSignCallback: PresentationSignCallback = async ( }, }) - const header = { - ...presentation.kbJwt.header, - alg: 'ES256K', + const createSignerVerifier = async () => { + const { privateKey, publicKey } = await ES256.generateKeyPair(); + return { + signer: await ES256.getSigner(privateKey), + verifier: await ES256.getVerifier(publicKey) + } } - const payload = { - ...presentation.kbJwt.payload, - aud: '123', + + const { signer, verifier } = await createSignerVerifier(); + + const sdjwt = new SDJwtVcInstance({ + signer, + signAlg: ES256.alg, + verifier, + hasher: digest, + saltGenerator: generateSalt, + kbSigner: signer, + kbSignAlg: ES256.alg, + kbVerifier: verifier + }) + + const claims = { + license: { + number: 10 + }, + user: { + name: 'John', + date_of_birth: '01/01/1970' + } } - const kbJwtCompact = `${Buffer.from(JSON.stringify(header)).toString('base64url')}.${Buffer.from(JSON.stringify(payload)).toString('base64url')}.signature` - return presentation.compactSdJwtVc + kbJwtCompact + const kbPayload: Omit = presentation.kbJwt.payload + + presentation.compactSdJwtVc = await sdjwt.present( + presentation.compactSdJwtVc, + { + user: { name: true }, + license: { number: true } + }, + { + kb: { + payload: kbPayload, + }, + }, + ); + + return presentation.compactSdJwtVc } diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 4e9ac139..ed9da3a3 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -44,6 +44,9 @@ "@digitalcredentials/ed25519-signature-2020": "^3.0.2", "@digitalcredentials/jsonld-signatures": "^9.3.2", "@digitalcredentials/vc": "^6.0.0", + "@sd-jwt/crypto-nodejs": "0.7.2", + "@sd-jwt/sd-jwt-vc": "0.7.2", + "@sd-jwt/types": "0.7.2", "@sphereon/wellknown-dids-client": "^0.1.3", "@sphereon/did-uni-client": "^0.6.2", "@transmute/did-key-ed25519": "^0.3.0-unstable.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f12956d5..df2ed3fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -523,6 +523,15 @@ importers: '@digitalcredentials/vc': specifier: ^6.0.0 version: 6.0.1(encoding@0.1.13)(expo@48.0.21(@babel/core@7.26.0)(encoding@0.1.13))(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@sd-jwt/crypto-nodejs': + specifier: 0.7.2 + version: 0.7.2 + '@sd-jwt/sd-jwt-vc': + specifier: 0.7.2 + version: 0.7.2 + '@sd-jwt/types': + specifier: 0.7.2 + version: 0.7.2 '@sphereon/did-uni-client': specifier: ^0.6.2 version: 0.6.3(encoding@0.1.13) @@ -2451,14 +2460,30 @@ packages: '@scure/base@1.2.1': resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} + '@sd-jwt/core@0.7.2': + resolution: {integrity: sha512-vix1GplUFc1A9H42r/yXkg7cKYthggyqZEwlFdsBbn4xdZNE+AHVF4N7kPa1pPxipwN3UIHd4XnQ5MJV15mhsQ==} + engines: {node: '>=18'} + + '@sd-jwt/crypto-nodejs@0.7.2': + resolution: {integrity: sha512-7DHy1WBHwvXseiX+U7XA6jX4dX4Ins3Nxd12JhBSm+FJfIwU97FU/H0KlF6lLyi4a4nbY/O6U9wJjYI1PxA9sQ==} + engines: {node: '>=18'} + '@sd-jwt/decode@0.7.2': resolution: {integrity: sha512-dan2LSvK63SKwb62031G4r7TE4TaiI0EK1KbPXqS+LCXNkNDUHqhtYp9uOpj+grXceCsMtMa2f8VnUfsjmwHHg==} engines: {node: '>=18'} + '@sd-jwt/jwt-status-list@0.7.2': + resolution: {integrity: sha512-o/Mg/Zg21poFsPXuxtPD9sdXq2b/0L+rb9gxU2k1rp1aT+DWmqD0k8v0Ttr2tlMc8l1xXQNA8FLXbL1AdLRmbQ==} + engines: {node: '>=18'} + '@sd-jwt/present@0.7.2': resolution: {integrity: sha512-mQV85u2+mLLy2VZ9Wx2zpaB6yTDnbhCfWkP7eeCrzJQHBKAAHko8GrylEFmLKewFIcajS/r4lT/zHOsCkp5pZw==} engines: {node: '>=18'} + '@sd-jwt/sd-jwt-vc@0.7.2': + resolution: {integrity: sha512-rryYmnoJHRSNqHcrs0Atta+bfJzU2yT7mYumR2D4lTfxJKWZd0OHHFq57uZSEm/wXPI6uytUJXYbEboCqLUAtw==} + engines: {node: '>=18'} + '@sd-jwt/types@0.7.2': resolution: {integrity: sha512-1NRKowiW0ZiB9SGLApLPBH4Xk8gDQJ+nA9NdZ+uy6MmJKLEwjuJxO7yTvRIv/jX/0/Ebh339S7Kq4RD2AiFuRg==} engines: {node: '>=18'} @@ -11774,17 +11799,38 @@ snapshots: '@scure/base@1.2.1': {} + '@sd-jwt/core@0.7.2': + dependencies: + '@sd-jwt/decode': 0.7.2 + '@sd-jwt/present': 0.7.2 + '@sd-jwt/types': 0.7.2 + '@sd-jwt/utils': 0.7.2 + + '@sd-jwt/crypto-nodejs@0.7.2': {} + '@sd-jwt/decode@0.7.2': dependencies: '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 + '@sd-jwt/jwt-status-list@0.7.2': + dependencies: + '@sd-jwt/types': 0.7.2 + base64url: 3.0.1 + pako: 2.1.0 + '@sd-jwt/present@0.7.2': dependencies: '@sd-jwt/decode': 0.7.2 '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 + '@sd-jwt/sd-jwt-vc@0.7.2': + dependencies: + '@sd-jwt/core': 0.7.2 + '@sd-jwt/jwt-status-list': 0.7.2 + '@sd-jwt/utils': 0.7.2 + '@sd-jwt/types@0.7.2': {} '@sd-jwt/utils@0.7.2': From 5674a275c8ed7f8e0b9c58599131735218f20c90 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 3 Jan 2025 16:14:21 +0100 Subject: [PATCH 27/48] Fix: Updated the response mode in test --- packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts b/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts index f916e415..8045e1f7 100644 --- a/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts @@ -234,7 +234,7 @@ describe('Mattr OID4VP v18 credential offer', () => { }) expect(verification).toBeDefined() - expect(verification.versions).toEqual([SupportedVersion.SIOPv2_D12_OID4VP_D20, SupportedVersion.SIOPv2_D12_OID4VP_D18]) + expect(verification.versions).toEqual([SupportedVersion.SIOPv2_D12_OID4VP_D18]) /** * pd value: {"id":"dae5d9b6-8145-4297-99b2-b8fcc5abb5ad","input_descriptors":[{"id":"OpenBadgeCredential","format":{"jwt_vc_json":{"alg":["EdDSA"]},"jwt_vc":{"alg":["EdDSA"]}},"constraints":{"fields":[{"path":["$.vc.type"],"filter":{"type":"array","items":{"type":"string"},"contains":{"const":"OpenBadgeCredential"}}}]}}]} From fd6a07bf6e92dbbc8ed77d4f7f5a5fa8bc7c34c0 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 8 Jan 2025 10:27:58 +0100 Subject: [PATCH 28/48] Refactor: Disabled tests again --- packages/siop-oid4vp/lib/__tests__/IT.spec.ts | 2 +- packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/IT.spec.ts b/packages/siop-oid4vp/lib/__tests__/IT.spec.ts index 8bb15898..ee892a58 100644 --- a/packages/siop-oid4vp/lib/__tests__/IT.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/IT.spec.ts @@ -141,7 +141,7 @@ function getVCs(): IVerifiableCredential[] { return vcs } -describe('RP and OP interaction should', () => { +describe.skip('RP and OP interaction should', () => { // FIXME SDK-45 Uniresolver failing it( 'succeed when calling each other in the full flow', diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index d2614c30..457a983b 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -103,7 +103,7 @@ function getVCs(): OriginalVerifiableCredential[] { return [SD_JWT_VC] } -describe('RP and OP interaction should', () => { +describe.skip('RP and OP interaction should', () => { // FIXME SDK-45 Uniresolver failing it('succeed when calling with presentation definitions and right verifiable presentation', async () => { const opMock = await mockedGetEnterpriseAuthToken('OP') From d0023791635f3866bfc09011d6a79a407b9d22d2 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 8 Jan 2025 13:42:31 +0100 Subject: [PATCH 29/48] Refactor: Rolled back the changes in response type and updated DCQL library. --- package.json | 2 +- .../AuthenticationResponse.response.spec.ts | 13 ++++---- .../siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 10 +++---- .../lib/__tests__/e2e/mattr.launchpad.spec.ts | 2 +- .../lib/helpers/SIOPSpecVersion.ts | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 30 +++++++++---------- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 3fb16fb7..22d624ea 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "resolutions": { "@sphereon/ssi-types": "0.32.0", - "dcql": "0.2.11", + "dcql": "0.2.17", "node-fetch": "2.6.12" }, "prettier": { diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index a82a730e..368ff707 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -8,7 +8,7 @@ import { IVerifiablePresentation, OriginalVerifiableCredential, } from '@sphereon/ssi-types' -import { DcqlCredentialRepresentation, DcqlPresentationRecord, DcqlQuery, DcqlQueryResult } from 'dcql' +import { DcqlCredential, DcqlPresentation, DcqlQuery, DcqlQueryResult } from 'dcql' import { AuthorizationResponse, @@ -28,7 +28,7 @@ import { VerifyAuthorizationRequestOpts, VPTokenLocation, } from '..' -import { createPresentationSubmission } from '../authorization-response/OpenID4VP' +import { createPresentationSubmission } from '../authorization-response' import SIOPErrors from '../types/Errors' import { getCreateJwtCallback, getVerifyJwtCallback } from './DidJwtTestUtils' @@ -749,21 +749,22 @@ describe('create JWT from Request JWT should', () => { }, } - const vc: DcqlCredentialRepresentation = { + const vc: DcqlCredential = { + credential_format: 'vc+sd-jwt', vct: sdjwt.decodedPayload.payload.vct, claims: sdjwt.decodedPayload.payload, } const dcqlQueryResult: DcqlQueryResult = DcqlQuery.query(dcqlQuery, [vc]) - const presentation: DcqlPresentationRecord.Output = {} + const presentation: DcqlPresentation.Output = {} for (const [key, value] of Object.entries(dcqlQueryResult.credential_matches)) { if (value.success) { presentation[key] = sdjwt.compactJwtVc } } - const encodedPresentationRecord = DcqlPresentationRecord.parse(presentation) + const dcqlPresentation = DcqlPresentation.parse(presentation) const responseOpts: AuthorizationResponseOpts = { responseURI: EXAMPLE_REDIRECT_URL, @@ -776,7 +777,7 @@ describe('create JWT from Request JWT should', () => { }), jwtIssuer: { method: 'did', didUrl: `${mockResEntity.did}#controller`, alg: SigningAlgo.ES256K }, dcqlQuery: { - encodedPresentationRecord, + dcqlPresentation }, responseMode: ResponseMode.DIRECT_POST, } diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index 457a983b..36f50a26 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -1,7 +1,7 @@ import { defaultHasher, SigningAlgo } from '@sphereon/oid4vc-common' import { IPresentationDefinition } from '@sphereon/pex' import { decodeSdJwtVc, OriginalVerifiableCredential } from '@sphereon/ssi-types' -import { DcqlCredentialRepresentation, DcqlQuery } from 'dcql' +import { DcqlCredential, DcqlQuery } from 'dcql' import { Json } from 'dcql/dist/src/u-dcql' import { @@ -438,7 +438,7 @@ describe.skip('RP and OP interaction should', () => { expect(verifiedAuthReqWithJWT.issuer).toMatch(rpMockEntity.did) // The KB property is added to the JWT when the presentation is signed. Passing a VC will make the test fail - const dcqlCredentials: DcqlCredentialRepresentation[] = [KB_SD_JWT_PRESENTATION].map(vc => ({ claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json }, vct: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload.vct } )) + const dcqlCredentials: DcqlCredential[] = [KB_SD_JWT_PRESENTATION].map(vc => ({ credential_format: 'vc+sd-jwt', claims: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload as { [x: string]: Json }, vct: decodeSdJwtVc(vc as string, defaultHasher).decodedPayload.vct } )) const queryResult = DcqlQuery.query(sdJwtVcQuery, dcqlCredentials) @@ -509,14 +509,14 @@ describe.skip('RP and OP interaction should', () => { ] }) - const encodedPresentationRecord: { [x: string]: string | { [x: string]: Json } } = {} + const dcqlPresentation: { [x: string]: string | { [x: string]: Json } } = {} for (const [key, _] of Object.entries(queryResult.credential_matches)) { - encodedPresentationRecord[key] = KB_SD_JWT_PRESENTATION as string | { [x: string]: Json } + dcqlPresentation[key] = KB_SD_JWT_PRESENTATION as string | { [x: string]: Json } } const authenticationResponseWithJWT = await op.createAuthorizationResponse(verifiedAuthReqWithJWT, { - dcqlQuery: { encodedPresentationRecord }, + dcqlQuery: { dcqlPresentation }, }) expect(authenticationResponseWithJWT.response.payload).toBeDefined() expect(authenticationResponseWithJWT.response.idToken).toBeDefined() diff --git a/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts b/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts index 8045e1f7..f916e415 100644 --- a/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/e2e/mattr.launchpad.spec.ts @@ -234,7 +234,7 @@ describe('Mattr OID4VP v18 credential offer', () => { }) expect(verification).toBeDefined() - expect(verification.versions).toEqual([SupportedVersion.SIOPv2_D12_OID4VP_D18]) + expect(verification.versions).toEqual([SupportedVersion.SIOPv2_D12_OID4VP_D20, SupportedVersion.SIOPv2_D12_OID4VP_D18]) /** * pd value: {"id":"dae5d9b6-8145-4297-99b2-b8fcc5abb5ad","input_descriptors":[{"id":"OpenBadgeCredential","format":{"jwt_vc_json":{"alg":["EdDSA"]},"jwt_vc":{"alg":["EdDSA"]}},"constraints":{"fields":[{"path":["$.vc.type"],"filter":{"type":"array","items":{"type":"string"},"contains":{"const":"OpenBadgeCredential"}}}]}}]} diff --git a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts index 8efa2b9a..5e41e4e8 100644 --- a/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts +++ b/packages/siop-oid4vp/lib/helpers/SIOPSpecVersion.ts @@ -44,7 +44,7 @@ export const authorizationRequestVersionDiscovery = (authorizationRequest: Autho !authorizationRequestCopy.registration_uri && !authorizationRequestCopy.registration && !(authorizationRequestCopy.claims && 'vp_token' in authorizationRequestCopy.claims) && - authorizationRequestCopy.response_mode !== ResponseMode.DIRECT_POST // Post has been replaced by direct post + authorizationRequestCopy.response_mode !== ResponseMode.POST // Post has been replaced by direct post ) { versions.push(SupportedVersion.SIOPv2_D12_OID4VP_D20) } diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index ed9da3a3..2a64b9ca 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.28", - "dcql": "0.2.11", + "dcql": "0.2.17", "@sphereon/pex-models": "^2.3.2", "@sphereon/ssi-types": "0.32.0", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df2ed3fd..c6c2bb15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: '@sphereon/ssi-types': 0.32.0 - dcql: 0.2.11 + dcql: 0.2.17 node-fetch: 2.6.12 importers: @@ -460,8 +460,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: 0.2.11 - version: 0.2.11(typescript@5.4.5) + specifier: 0.2.17 + version: 0.2.17(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -4033,8 +4033,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.11: - resolution: {integrity: sha512-hR8MuSx49b7JPoZztcFMSKEHc6iEE4l/Zs6aUsvMCWVa3qFWpuJRiJEp5Rh2+UkCAhsce94fbDpMdBTcS9zn7g==} + dcql@0.2.17: + resolution: {integrity: sha512-YKNJR2anEiWooUCg7cJt/QmSFxpBS+SJQurcsNA60+8qUrjOuroh1Wd+lka/yOAV2VUdRzdNY6ISouxTV6SUaQ==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -8395,16 +8395,16 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@0.37.0: - resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + valibot@0.42.1: + resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: typescript: '>=5' peerDependenciesMeta: typescript: optional: true - valibot@0.42.1: - resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} + valibot@1.0.0-beta.8: + resolution: {integrity: sha512-OPAwJZtowb0j91b+bd77+ny7D1VVzsCzD7Jl9waLUlMprTsfI9Y3HHbW3hAQD7wKDKHsmGEesuiYWaYvcZL2wg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -13947,9 +13947,9 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.11(typescript@5.4.5): + dcql@0.2.17(typescript@5.4.5): dependencies: - valibot: 0.37.0(typescript@5.4.5) + valibot: 1.0.0-beta.8(typescript@5.4.5) transitivePeerDependencies: - typescript @@ -19613,14 +19613,14 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@0.37.0(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - valibot@0.42.1(typescript@5.5.3): optionalDependencies: typescript: 5.5.3 + valibot@1.0.0-beta.8(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + valid-url@1.0.9: {} validate-npm-package-license@3.0.4: From 43420cfd58ff89f4fdfe6da329e9098b6ff99dfd Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 8 Jan 2025 14:34:58 +0100 Subject: [PATCH 30/48] refactor: Checking whether PDs and DCQL are present --- packages/siop-oid4vp/lib/rp/RP.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index be7fc1fb..e529aee8 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -415,6 +415,16 @@ export class RP { } } + const hasPD = (this._verifyResponseOptions.presentationDefinitions !== undefined && this._verifyResponseOptions.presentationDefinitions !== null || (Array.isArray(this._verifyResponseOptions.presentationDefinitions) && this._verifyResponseOptions.presentationDefinitions.length > 0)) || + (opts.presentationDefinitions !== undefined && opts.presentationDefinitions !== null || (Array.isArray(opts.presentationDefinitions) && opts.presentationDefinitions.length > 0)) + const hasDcql = (this._verifyResponseOptions.dcqlQuery !== undefined && this._verifyResponseOptions.dcqlQuery !== null) || (opts.dcqlQuery !== undefined && opts.dcqlQuery !== null) + + if (hasPD && hasDcql) { + throw Error(`Only Presentation Definitions or DCQL is required`) + } else if (!hasPD && !hasDcql) { + throw Error(`Either a Presentation Definition or DCQL is required`) + } + return { ...this._verifyResponseOptions, verifyJwtCallback: this._verifyResponseOptions.verifyJwtCallback, @@ -424,12 +434,8 @@ export class RP { state, nonce, verification: mergeVerificationOpts(this._verifyResponseOptions, opts), - ...(opts?.presentationDefinitions && !opts?.dcqlQuery && { - presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions - }), - ...(opts?.dcqlQuery && !opts?.presentationDefinitions && { - dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery - }) + presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions, + dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery } } From 44821ee73aaea1f5339d25fa1f92e27f6ecc8092 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 8 Jan 2025 14:52:53 +0100 Subject: [PATCH 31/48] refactor: Removed pnpm version limitation --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 22d624ea..2c1839dd 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,5 @@ "OIDC4VP", "OID4VCI", "OID4VP" - ], - "packageManager": "pnpm@9.6.0+sha256.dae0f7e822c56b20979bb5965e3b73b8bdabb6b8b8ef121da6d857508599ca35" + ] } From d6d751a1aa3e13686915c353458b292882edff2e Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 13:55:49 +0100 Subject: [PATCH 32/48] chore: lib updates --- package.json | 2 +- packages/callback-example/package.json | 2 +- packages/client/package.json | 2 +- packages/common/package.json | 2 +- packages/issuer-rest/package.json | 2 +- packages/issuer/package.json | 2 +- packages/oid4vci-common/package.json | 2 +- .../AuthorizationResponse.ts | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 46 +++++++++---------- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index e1482a95..c54e1b0d 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "resolutions": { - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "dcql": "0.2.11", "node-fetch": "2.6.12" }, diff --git a/packages/callback-example/package.json b/packages/callback-example/package.json index bb1dd3e1..b157f874 100644 --- a/packages/callback-example/package.json +++ b/packages/callback-example/package.json @@ -19,7 +19,7 @@ "@sphereon/oid4vci-client": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "jose": "^4.10.0" }, "devDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index 5e7acb8a..0389786f 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,7 +17,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "cross-fetch": "^3.1.8", "debug": "^4.3.5" }, diff --git a/packages/common/package.json b/packages/common/package.json index 04ea2a3d..cf2238e9 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -10,7 +10,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "jwt-decode": "^4.0.0", "sha.js": "^2.4.11", "uint8arrays": "3.1.1", diff --git a/packages/issuer-rest/package.json b/packages/issuer-rest/package.json index 5c3007e0..8cd4d858 100644 --- a/packages/issuer-rest/package.json +++ b/packages/issuer-rest/package.json @@ -15,7 +15,7 @@ "@sphereon/oid4vci-common": "workspace:*", "@sphereon/oid4vci-issuer": "workspace:*", "@sphereon/ssi-express-support": "0.30.2-feature.mdoc.funke2.367", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "body-parser": "^1.20.2", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/packages/issuer/package.json b/packages/issuer/package.json index ea3d1f4f..e35aa0c2 100644 --- a/packages/issuer/package.json +++ b/packages/issuer/package.json @@ -12,7 +12,7 @@ "dependencies": { "@sphereon/oid4vc-common": "workspace:*", "@sphereon/oid4vci-common": "workspace:*", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "uuid": "^9.0.0" }, "peerDependencies": { diff --git a/packages/oid4vci-common/package.json b/packages/oid4vci-common/package.json index ffcfdb85..5ae90beb 100644 --- a/packages/oid4vci-common/package.json +++ b/packages/oid4vci-common/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@sphereon/oid4vc-common": "workspace:*", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "cross-fetch": "^3.1.8", "debug": "^4.3.5", "jwt-decode": "^4.0.0", diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 0e2c8112..69078199 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -229,7 +229,7 @@ export class AuthorizationResponse { } public async getMergedProperty(key: string, opts?: { consistencyCheck?: boolean; hasher?: Hasher }): Promise { - const merged = await this.mergedPayloads(opts) + const merged = await this.mergedPayloads(opts) // FIXME this is really bad, expensive... return merged[key] as T } diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index 2e98f766..d10ab9cf 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -20,7 +20,7 @@ "@sphereon/pex": "5.0.0-unstable.28", "dcql": "0.2.11", "@sphereon/pex-models": "^2.3.2", - "@sphereon/ssi-types": "0.32.1-feature.VDX.341.27", + "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "cross-fetch": "^4.0.0", "debug": "^4.3.5", "events": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 73d98481..04068952 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.53 dcql: 0.2.11 node-fetch: 2.6.12 @@ -77,8 +77,8 @@ importers: specifier: workspace:* version: link:../issuer '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 jose: specifier: ^4.10.0 version: 4.15.9 @@ -120,8 +120,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -205,8 +205,8 @@ importers: packages/common: dependencies: '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 jwt-decode: specifier: ^4.0.0 version: 4.0.0 @@ -270,8 +270,8 @@ importers: specifier: workspace:* version: link:../oid4vci-common '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -313,8 +313,8 @@ importers: specifier: 0.30.2-feature.mdoc.funke2.367 version: 0.30.2-feature.mdoc.funke2.367 '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 awesome-qr: specifier: ^2.1.5-rc.0 version: 2.1.5-rc.0(encoding@0.1.13) @@ -405,8 +405,8 @@ importers: specifier: workspace:* version: link:../common '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 cross-fetch: specifier: ^3.1.8 version: 3.1.8(encoding@0.1.13) @@ -454,8 +454,8 @@ importers: specifier: ^2.3.2 version: 2.3.2 '@sphereon/ssi-types': - specifier: 0.32.1-feature.VDX.341.27 - version: 0.32.1-feature.VDX.341.27 + specifier: 0.32.1-feature.VDX.341.53 + version: 0.32.1-feature.VDX.341.53 cross-fetch: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) @@ -2565,8 +2565,8 @@ packages: '@sphereon/ssi-sdk-ext.key-utils@0.23.0': resolution: {integrity: sha512-BfULXvQmcUrBq2DqYxJHKnEoB2d5icu3TJ9GP2aP1WybSULTjL96Wv5r7QKgktcodKaL+F+oQ7r8sC9qBl1exw==} - '@sphereon/ssi-types@0.32.1-feature.VDX.341.27': - resolution: {integrity: sha512-Mw72f13IckggZmQ2uXlcq/gHgwoV+Mqtj3/SyBHZrxkvAq9LpWynImrlgiQDkBGlvpQ3chZ/ju8pQIPDTIqFWA==} + '@sphereon/ssi-types@0.32.1-feature.VDX.341.53': + resolution: {integrity: sha512-SC5GMqMZDILQJLGUddXjkVmSHIsDevp/ANVRGtLsWQK1pt3272eOA6Xq0yBMaAFmknYlisHMOf29JlYLJy/fZw==} '@sphereon/wellknown-dids-client@0.1.3': resolution: {integrity: sha512-TAT24L3RoXD8ocrkTcsz7HuJmgjNjdoV6IXP1p3DdaI/GqkynytXE3J1+F7vUFMRYwY5nW2RaXSgDQhrFJemaA==} @@ -10026,7 +10026,7 @@ snapshots: '@digitalcredentials/bnid@2.1.2(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1))': dependencies: '@digitalcredentials/base58-universal': 1.0.1 - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) yargs: 15.4.1 transitivePeerDependencies: - react-native @@ -11875,7 +11875,7 @@ snapshots: webcrypto-shim: 0.1.7 optionalDependencies: expo: 48.0.21(@babel/core@7.26.0)(encoding@0.1.13) - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': dependencies: @@ -11892,7 +11892,7 @@ snapshots: '@sd-jwt/present': 0.7.2 '@sd-jwt/types': 0.7.2 '@sphereon/pex-models': 2.3.2 - '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.53 ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) jwt-decode: 3.1.2 @@ -11944,7 +11944,7 @@ snapshots: - react-native-securerandom - supports-color - '@sphereon/ssi-types@0.32.1-feature.VDX.341.27': + '@sphereon/ssi-types@0.32.1-feature.VDX.341.53': dependencies: '@sd-jwt/decode': 0.7.2 '@sphereon/kmp-mdoc-core': 0.2.0-SNAPSHOT.26 @@ -11957,7 +11957,7 @@ snapshots: '@sphereon/wellknown-dids-client@0.1.3(encoding@0.1.13)': dependencies: - '@sphereon/ssi-types': 0.32.1-feature.VDX.341.27 + '@sphereon/ssi-types': 0.32.1-feature.VDX.341.53 cross-fetch: 3.1.8(encoding@0.1.13) jwt-decode: 3.1.2 transitivePeerDependencies: @@ -18213,7 +18213,7 @@ snapshots: react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) optional: true - react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)): + react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)): dependencies: base64-js: 1.5.1 react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) From 4ff1d70052db080d516e27b94555baef77232ea7 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 15:32:57 +0100 Subject: [PATCH 33/48] chore: dcql update --- package.json | 2 +- packages/siop-oid4vp/package.json | 2 +- pnpm-lock.yaml | 77 +++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index c54e1b0d..a13ec126 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "resolutions": { "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", - "dcql": "0.2.11", + "dcql": "0.2.19", "node-fetch": "2.6.12" }, "prettier": { diff --git a/packages/siop-oid4vp/package.json b/packages/siop-oid4vp/package.json index aad9056a..4978ce14 100644 --- a/packages/siop-oid4vp/package.json +++ b/packages/siop-oid4vp/package.json @@ -18,7 +18,7 @@ "@sphereon/jarm": "workspace:*", "@sphereon/oid4vc-common": "workspace:*", "@sphereon/pex": "5.0.0-unstable.28", - "dcql": "0.2.17", + "dcql": "0.2.19", "@sphereon/pex-models": "^2.3.2", "@sphereon/ssi-types": "0.32.1-feature.VDX.341.53", "cross-fetch": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 04068952..a90f84f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: '@sphereon/ssi-types': 0.32.1-feature.VDX.341.53 - dcql: 0.2.11 + dcql: 0.2.19 node-fetch: 2.6.12 importers: @@ -460,8 +460,8 @@ importers: specifier: ^4.0.0 version: 4.0.0(encoding@0.1.13) dcql: - specifier: 0.2.11 - version: 0.2.11(typescript@5.4.5) + specifier: 0.2.19 + version: 0.2.19(typescript@5.4.5) debug: specifier: ^4.3.5 version: 4.3.7 @@ -523,6 +523,15 @@ importers: '@digitalcredentials/vc': specifier: ^6.0.0 version: 6.0.1(encoding@0.1.13)(expo@48.0.21(@babel/core@7.26.0)(encoding@0.1.13))(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@sd-jwt/crypto-nodejs': + specifier: 0.7.2 + version: 0.7.2 + '@sd-jwt/sd-jwt-vc': + specifier: 0.7.2 + version: 0.7.2 + '@sd-jwt/types': + specifier: 0.7.2 + version: 0.7.2 '@sphereon/did-uni-client': specifier: ^0.6.2 version: 0.6.3(encoding@0.1.13) @@ -2451,14 +2460,30 @@ packages: '@scure/base@1.2.1': resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} + '@sd-jwt/core@0.7.2': + resolution: {integrity: sha512-vix1GplUFc1A9H42r/yXkg7cKYthggyqZEwlFdsBbn4xdZNE+AHVF4N7kPa1pPxipwN3UIHd4XnQ5MJV15mhsQ==} + engines: {node: '>=18'} + + '@sd-jwt/crypto-nodejs@0.7.2': + resolution: {integrity: sha512-7DHy1WBHwvXseiX+U7XA6jX4dX4Ins3Nxd12JhBSm+FJfIwU97FU/H0KlF6lLyi4a4nbY/O6U9wJjYI1PxA9sQ==} + engines: {node: '>=18'} + '@sd-jwt/decode@0.7.2': resolution: {integrity: sha512-dan2LSvK63SKwb62031G4r7TE4TaiI0EK1KbPXqS+LCXNkNDUHqhtYp9uOpj+grXceCsMtMa2f8VnUfsjmwHHg==} engines: {node: '>=18'} + '@sd-jwt/jwt-status-list@0.7.2': + resolution: {integrity: sha512-o/Mg/Zg21poFsPXuxtPD9sdXq2b/0L+rb9gxU2k1rp1aT+DWmqD0k8v0Ttr2tlMc8l1xXQNA8FLXbL1AdLRmbQ==} + engines: {node: '>=18'} + '@sd-jwt/present@0.7.2': resolution: {integrity: sha512-mQV85u2+mLLy2VZ9Wx2zpaB6yTDnbhCfWkP7eeCrzJQHBKAAHko8GrylEFmLKewFIcajS/r4lT/zHOsCkp5pZw==} engines: {node: '>=18'} + '@sd-jwt/sd-jwt-vc@0.7.2': + resolution: {integrity: sha512-rryYmnoJHRSNqHcrs0Atta+bfJzU2yT7mYumR2D4lTfxJKWZd0OHHFq57uZSEm/wXPI6uytUJXYbEboCqLUAtw==} + engines: {node: '>=18'} + '@sd-jwt/types@0.7.2': resolution: {integrity: sha512-1NRKowiW0ZiB9SGLApLPBH4Xk8gDQJ+nA9NdZ+uy6MmJKLEwjuJxO7yTvRIv/jX/0/Ebh339S7Kq4RD2AiFuRg==} engines: {node: '>=18'} @@ -2540,6 +2565,7 @@ packages: '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': resolution: {integrity: sha512-QXJ6R8ENiZV2rPMbn06cw5JKwqUYN1kzVRbYfONqE1PEXx1noQ4md7uxr2zSczi0ubKkNcbyYDNtIMTZIhGzmQ==} + bundledDependencies: [] '@sphereon/pex-models@2.3.2': resolution: {integrity: sha512-foFxfLkRwcn/MOp/eht46Q7wsvpQGlO7aowowIIb5Tz9u97kYZ2kz6K2h2ODxWuv5CRA7Q0MY8XUBGE2lfOhOQ==} @@ -4007,8 +4033,8 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dcql@0.2.11: - resolution: {integrity: sha512-hR8MuSx49b7JPoZztcFMSKEHc6iEE4l/Zs6aUsvMCWVa3qFWpuJRiJEp5Rh2+UkCAhsce94fbDpMdBTcS9zn7g==} + dcql@0.2.19: + resolution: {integrity: sha512-/EvT8tArlg8zFsTQbRn6PijfeQ3nUwuEeCRDpptWcYqE8Wyt8J9Sb44gMPFzVCoIEb3R0M7Hl+XWkUMobC8jXQ==} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -8369,16 +8395,16 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@0.37.0: - resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + valibot@0.42.1: + resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: typescript: '>=5' peerDependenciesMeta: typescript: optional: true - valibot@0.42.1: - resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} + valibot@1.0.0-beta.8: + resolution: {integrity: sha512-OPAwJZtowb0j91b+bd77+ny7D1VVzsCzD7Jl9waLUlMprTsfI9Y3HHbW3hAQD7wKDKHsmGEesuiYWaYvcZL2wg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -11773,17 +11799,38 @@ snapshots: '@scure/base@1.2.1': {} + '@sd-jwt/core@0.7.2': + dependencies: + '@sd-jwt/decode': 0.7.2 + '@sd-jwt/present': 0.7.2 + '@sd-jwt/types': 0.7.2 + '@sd-jwt/utils': 0.7.2 + + '@sd-jwt/crypto-nodejs@0.7.2': {} + '@sd-jwt/decode@0.7.2': dependencies: '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 + '@sd-jwt/jwt-status-list@0.7.2': + dependencies: + '@sd-jwt/types': 0.7.2 + base64url: 3.0.1 + pako: 2.1.0 + '@sd-jwt/present@0.7.2': dependencies: '@sd-jwt/decode': 0.7.2 '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 + '@sd-jwt/sd-jwt-vc@0.7.2': + dependencies: + '@sd-jwt/core': 0.7.2 + '@sd-jwt/jwt-status-list': 0.7.2 + '@sd-jwt/utils': 0.7.2 + '@sd-jwt/types@0.7.2': {} '@sd-jwt/utils@0.7.2': @@ -13900,9 +13947,9 @@ snapshots: dayjs@1.11.13: {} - dcql@0.2.11(typescript@5.4.5): + dcql@0.2.19(typescript@5.4.5): dependencies: - valibot: 0.37.0(typescript@5.4.5) + valibot: 1.0.0-beta.8(typescript@5.4.5) transitivePeerDependencies: - typescript @@ -19566,14 +19613,14 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@0.37.0(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - valibot@0.42.1(typescript@5.5.3): optionalDependencies: typescript: 5.5.3 + valibot@1.0.0-beta.8(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + valid-url@1.0.9: {} validate-npm-package-license@3.0.4: From 7e8a5fd262b10ddc745462223b0f58b7bf7d84f2 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 15:57:49 +0100 Subject: [PATCH 34/48] chore: dcql fixes --- packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 8 ++++++-- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 3 ++- packages/siop-oid4vp/lib/types/SIOP.types.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index 36f50a26..1c504b52 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -2,7 +2,6 @@ import { defaultHasher, SigningAlgo } from '@sphereon/oid4vc-common' import { IPresentationDefinition } from '@sphereon/pex' import { decodeSdJwtVc, OriginalVerifiableCredential } from '@sphereon/ssi-types' import { DcqlCredential, DcqlQuery } from 'dcql' -import { Json } from 'dcql/dist/src/u-dcql' import { OP, @@ -35,6 +34,11 @@ import { jest.setTimeout(30000) +type Json = string | number | boolean | null | { // Not exported from dcql + [key: string]: Json; +} | Json[]; + + const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const HOLDER_DID = 'did:example:ebfeb1f712ebc6f1c276e12ec21' @@ -371,7 +375,7 @@ describe.skip('RP and OP interaction should', () => { .withResponseType([ResponseType.ID_TOKEN, ResponseType.VP_TOKEN]) .withResponseMode(ResponseMode.DIRECT_POST) .withRedirectUri(EXAMPLE_REDIRECT_URL) - .withDcqlQuery(JSON.stringify(sdJwtVcQuery), [PropertyTarget.REQUEST_OBJECT]) + .withDcqlQuery(sdJwtVcQuery, [PropertyTarget.REQUEST_OBJECT]) .withPresentationVerification(presentationVerificationCallback) .withRevocationVerification(RevocationVerification.NEVER) .withRequestBy(PassBy.VALUE) diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 2212994f..79a4ab3c 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -2,6 +2,7 @@ import { EventEmitter } from 'events' import { IPresentationDefinition } from '@sphereon/pex' import { Hasher } from '@sphereon/ssi-types' +import { DcqlQuery } from 'dcql' import { PropertyTarget, PropertyTargets } from '../authorization-request' import { PresentationVerificationCallback } from '../authorization-response' @@ -23,7 +24,7 @@ import { import { assignIfAuth, assignIfRequestObject, isTarget, isTargetOrNoTargets } from './Opts' import { RP } from './RP' import { IRPSessionManager } from './types' -import { DcqlQuery } from 'dcql' + export class RPBuilder { requestObjectBy: ObjectBy diff --git a/packages/siop-oid4vp/lib/types/SIOP.types.ts b/packages/siop-oid4vp/lib/types/SIOP.types.ts index 93db8bd2..54ff1b34 100644 --- a/packages/siop-oid4vp/lib/types/SIOP.types.ts +++ b/packages/siop-oid4vp/lib/types/SIOP.types.ts @@ -100,7 +100,7 @@ export interface AuthorizationRequestPayloadVD12OID4VPD20 presentation_definition_uri?: string client_id_scheme?: ClientIdSchemeOID4VPD20 response_uri?: string // New since OID4VP18 OPTIONAL. The Response URI to which the Wallet MUST send the Authorization Response using an HTTPS POST request as defined by the Response Mode direct_post. The Response URI receives all Authorization Response parameters as defined by the respective Response Type. When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error. - dcql_query?: DcqlQuery + dcql_query?: string } export type ClientIdSchemeOID4VPD18 = 'pre-registered' | 'redirect_uri' | 'entity_id' | 'did' From b28b39ef0652d4ce69fed7e7a3c6f6ae1479751e Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 16:20:50 +0100 Subject: [PATCH 35/48] chore: dcql fixes --- packages/siop-oid4vp/lib/rp/RP.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index e529aee8..185fa20f 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -434,8 +434,12 @@ export class RP { state, nonce, verification: mergeVerificationOpts(this._verifyResponseOptions, opts), - presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions, - dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery + ...(opts?.presentationDefinitions && !opts?.dcqlQuery && { + presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions + }), + ...(opts?.dcqlQuery && !opts?.presentationDefinitions && { + dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery + }) } } From 6e4e2ccb6cdf2f39e5b761b4b4ca4855dbfe2927 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 16:22:43 +0100 Subject: [PATCH 36/48] chore: dcql fixes --- packages/siop-oid4vp/lib/rp/RP.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index 185fa20f..e1faec4f 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -437,7 +437,8 @@ export class RP { ...(opts?.presentationDefinitions && !opts?.dcqlQuery && { presentationDefinitions: this._verifyResponseOptions.presentationDefinitions ?? opts?.presentationDefinitions }), - ...(opts?.dcqlQuery && !opts?.presentationDefinitions && { + ...(opts?.dcqlQuery /*&& !opts?.presentationDefinitions */&& { // FIXME presentationDefinitions will be there until we fix the OID4VC-DEMO, it wants a PD purpose field for the screens + dcqlQuery: this._verifyResponseOptions.dcqlQuery ?? opts?.dcqlQuery }) } From 7c0b5e131a83a27e8c160e983eac4cf492333ba9 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 17:07:09 +0100 Subject: [PATCH 37/48] chore: lockfile --- pnpm-lock.yaml | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a90f84f8..2fecd8fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -806,14 +806,12 @@ packages: '@babel/plugin-proposal-async-generator-functions@7.20.7': resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-proposal-class-properties@7.18.6': resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. peerDependencies: '@babel/core': ^7.0.0-0 @@ -832,35 +830,30 @@ packages: '@babel/plugin-proposal-export-namespace-from@7.18.9': resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead. peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6': resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-proposal-object-rest-spread@7.20.7': resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-proposal-optional-catch-binding@7.18.6': resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. peerDependencies: '@babel/core': ^7.0.0-0 '@babel/plugin-proposal-optional-chaining@7.21.0': resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. peerDependencies: '@babel/core': ^7.0.0-0 @@ -1982,7 +1975,6 @@ packages: '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -1990,7 +1982,6 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead '@hutson/parse-repository-url@3.0.2': resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} @@ -2237,7 +2228,6 @@ packages: '@npmcli/move-file@1.1.2': resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} engines: {node: '>=10'} - deprecated: This functionality has been moved to @npmcli/fs '@npmcli/name-from-folder@2.0.0': resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} @@ -3021,7 +3011,6 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} - deprecated: this version is no longer supported, please update to at least 0.8.* '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} @@ -3177,7 +3166,6 @@ packages: are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} - deprecated: This package is no longer supported. arg@4.1.0: resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} @@ -3437,7 +3425,6 @@ packages: boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -4465,7 +4452,6 @@ packages: eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -4858,7 +4844,6 @@ packages: gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} - deprecated: This package is no longer supported. gensequence@5.0.2: resolution: {integrity: sha512-JlKEZnFc6neaeSVlkzBGGgkIoIaSxMgvdamRoPN8r3ozm2r9dusqxeKqYQ7lhzmj2UhFQP8nkyfCaiLQxiLrDA==} @@ -4969,20 +4954,16 @@ packages: glob@6.0.4: resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} - deprecated: Glob versions prior to v9 are no longer supported glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} - deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -5225,7 +5206,6 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -6408,7 +6388,6 @@ packages: multibase@4.0.6: resolution: {integrity: sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ==} engines: {node: '>=12.0.0', npm: '>=6.0.0'} - deprecated: This module has been superseded by the multiformats module multiformats@12.1.3: resolution: {integrity: sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==} @@ -6604,7 +6583,6 @@ packages: npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} - deprecated: This package is no longer supported. nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -6746,7 +6724,6 @@ packages: osenv@0.1.5: resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} - deprecated: This package is no longer supported. p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} @@ -7408,22 +7385,18 @@ packages: rimraf@2.2.8: resolution: {integrity: sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==} - deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.4.5: resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} - deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@4.4.1: @@ -7857,7 +7830,6 @@ packages: superagent@8.1.2: resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} engines: {node: '>=6.4.0 <13 || >=14'} - deprecated: Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net supertest@6.3.4: resolution: {integrity: sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==} @@ -8240,7 +8212,6 @@ packages: uglify-es@3.3.9: resolution: {integrity: sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==} engines: {node: '>=0.8.0'} - deprecated: support for ECMAScript is superseded by `uglify-js` as of v3.13.0 hasBin: true uglify-js@3.19.3: @@ -8373,7 +8344,6 @@ packages: uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. hasBin: true uuid@7.0.3: From 0ea01253cb806bee270bb250bb2720ea964e19c8 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 13 Jan 2025 17:28:41 +0100 Subject: [PATCH 38/48] chore: force pnpm version --- .github/workflows/build-test-on-pr.yml | 2 +- .github/workflows/build-test-publish-on-push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test-on-pr.yml b/.github/workflows/build-test-on-pr.yml index fde1e54f..5bfb7892 100644 --- a/.github/workflows/build-test-on-pr.yml +++ b/.github/workflows/build-test-on-pr.yml @@ -25,7 +25,7 @@ jobs: node-version: '20.x' - uses: pnpm/action-setup@v4 with: - version: 9 + version: 9.15.3 - run: pnpm install - run: pnpm build - name: run CI tests diff --git a/.github/workflows/build-test-publish-on-push.yml b/.github/workflows/build-test-publish-on-push.yml index 450a530a..5ee72570 100644 --- a/.github/workflows/build-test-publish-on-push.yml +++ b/.github/workflows/build-test-publish-on-push.yml @@ -39,7 +39,7 @@ jobs: node-version: '20.x' - uses: pnpm/action-setup@v4 with: - version: 9 + version: 9.15.3 - run: pnpm install - run: pnpm build - name: run integration tests From 1ac490756b20acb3deb6652cb0ccdbbd1718644a Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 14 Jan 2025 09:43:21 +0100 Subject: [PATCH 39/48] chore: withDcqlQuery update --- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 79a4ab3c..84761720 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -228,22 +228,28 @@ export class RPBuilder { return this } - withDcqlQuery(dcqlQuery: DcqlQuery, targets?: PropertyTargets): RPBuilder { + withDcqlQuery(dcqlQuery: DcqlQuery | string, targets?: PropertyTargets): RPBuilder { if (this.getSupportedRequestVersion() >= SupportedVersion.SIOPv2_D12_OID4VP_D20) { this._authorizationRequestPayload.dcql_query = assignIfAuth( { - propertyValue: dcqlQuery, + propertyValue: typeof dcqlQuery === 'string' ? dcqlQuery : JSON.stringify(dcqlQuery), targets }, false ) this._requestObjectPayload.dcql_query = assignIfRequestObject( { - propertyValue: dcqlQuery, + propertyValue: typeof dcqlQuery === 'string' ? dcqlQuery : JSON.stringify(dcqlQuery), targets }, true ) + + // FIXME we need to find a way in the config to select dcql vs PD without breaking OID4VC-DEMO + this._authorizationRequestPayload.presentation_definition = undefined; + this._authorizationRequestPayload.presentation_definition_uri = undefined; + this._requestObjectPayload.presentation_definition = undefined; + this._requestObjectPayload.presentation_definition_uri = undefined; } return this } From 05d39b711781d495d7472d71101a038d6eefc793 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 14 Jan 2025 11:15:06 +0100 Subject: [PATCH 40/48] refactor: Allowed only presentation definition objects. --- packages/siop-oid4vp/lib/authorization-request/Payload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index 07290006..8d8d47e0 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -26,7 +26,7 @@ export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadO return undefined } - if (opts.vp_token.presentation_definition || opts.vp_token.presentation_definition_uri) { + if (opts.vp_token.presentation_definition !== undefined && opts.vp_token.presentation_definition !== null) { const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) if (discoveryResult.error) { throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) From ec6a13e146adbc40dd1ed3dac7c3249329742860 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 14 Jan 2025 11:43:18 +0100 Subject: [PATCH 41/48] refactor: Moved Dcql.ts functions into a Dcql class and made them static. --- .../AuthorizationRequest.ts | 6 +- .../lib/authorization-request/URI.ts | 4 +- .../AuthorizationResponse.ts | 4 +- .../lib/authorization-response/Dcql.ts | 96 +++++++++++-------- .../lib/authorization-response/OpenID4VP.ts | 4 +- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts index cc27b403..e7e1c0dc 100644 --- a/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts +++ b/packages/siop-oid4vp/lib/authorization-request/AuthorizationRequest.ts @@ -2,7 +2,7 @@ import { parseJWT } from '@sphereon/oid4vc-common' import { DcqlQuery } from 'dcql' import { PresentationDefinitionWithLocation } from '../authorization-response' -import { findValidDcqlQuery } from '../authorization-response' +import { Dcql } from '../authorization-response' import { PresentationExchange } from '../authorization-response/PresentationExchange' import { fetchByReferenceOrUseByValue, removeNullUndefined } from '../helpers' import { authorizationRequestVersionDiscovery } from '../helpers/SIOPSpecVersion' @@ -206,7 +206,7 @@ export class AuthorizationRequest { await this.getSupportedVersion(), ) - const dcqlQuery = await findValidDcqlQuery(mergedPayload) + const dcqlQuery = await Dcql.findValidDcqlQuery(mergedPayload) return { jwt, @@ -291,6 +291,6 @@ export class AuthorizationRequest { } public async getDcqlQuery(): Promise { - return await findValidDcqlQuery(await this.mergedPayloads()) + return await Dcql.findValidDcqlQuery(await this.mergedPayloads()) } } diff --git a/packages/siop-oid4vp/lib/authorization-request/URI.ts b/packages/siop-oid4vp/lib/authorization-request/URI.ts index f6bf42bc..1796b756 100644 --- a/packages/siop-oid4vp/lib/authorization-request/URI.ts +++ b/packages/siop-oid4vp/lib/authorization-request/URI.ts @@ -1,6 +1,6 @@ import { parseJWT } from '@sphereon/oid4vc-common' -import { findValidDcqlQuery } from '../authorization-response/Dcql' +import { Dcql } from '../authorization-response' import { PresentationExchange } from '../authorization-response/PresentationExchange' import { decodeUriAsJson, encodeJsonAsURI, fetchByReferenceOrUseByValue } from '../helpers' import { assertValidRequestObjectPayload, RequestObject } from '../request-object' @@ -166,7 +166,7 @@ export class URI implements AuthorizationRequestURI { if (requestObjectPayload) { // Only used to validate if the request object contains presentation definition(s) | a dcql query await PresentationExchange.findValidPresentationDefinitions({ ...authorizationRequestPayload, ...requestObjectPayload }) - await findValidDcqlQuery({ ...authorizationRequestPayload, ...requestObjectPayload }) + await Dcql.findValidDcqlQuery({ ...authorizationRequestPayload, ...requestObjectPayload }) assertValidRequestObjectPayload(requestObjectPayload) if (requestObjectPayload.registration) { diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 9bb0dcf4..78e7e301 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -6,7 +6,7 @@ import { assertValidVerifyAuthorizationRequestOpts } from '../authorization-requ import { IDToken } from '../id-token' import { AuthorizationResponsePayload, ResponseType, SIOPErrors, VerifiedAuthorizationRequest, VerifiedAuthorizationResponse } from '../types' -import { assertValidDcqlPresentationResult } from './Dcql' +import { Dcql } from './Dcql' import { assertValidVerifiablePresentations, extractNonceFromWrappedVerifiablePresentation, @@ -145,7 +145,7 @@ export class AuthorizationResponse { }, }) } else if (verifiedAuthorizationRequest.dcqlQuery) { - assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, verifiedAuthorizationRequest.dcqlQuery, { + await Dcql.assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, verifiedAuthorizationRequest.dcqlQuery, { hasher: verifyOpts.hasher, }) } else { diff --git a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts index 7740fdb3..f051fae0 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Dcql.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Dcql.ts @@ -13,50 +13,66 @@ import { extractDcqlPresentationFromDcqlVpToken } from './OpenID4VP' * @param authorizationRequestPayload object that can have a dcql_query inside * @param version */ -export const findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise => { - const dcqlQuery: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query').map((d) => d.value) - const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition') - const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]') - const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri') - const definitionRefsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri[*]') - - const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) - const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) - const hasDcql = dcqlQuery && dcqlQuery.length > 0 - - if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) { - throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) - } - if (dcqlQuery.length === 0) return undefined +export class Dcql { + + static findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise => { + const dcqlQuery: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query').map((d) => d.value) + const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition') + const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]') + const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri') + const definitionRefsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri[*]') + + const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0) + const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0) + const hasDcql = dcqlQuery && dcqlQuery.length > 0 + + if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) { + throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE) + } + + if (dcqlQuery.length === 0) return undefined - if (dcqlQuery.length > 1) { - throw new Error('Found multiple dcql_query in vp_token. Only one is allowed') + if (dcqlQuery.length > 1) { + throw new Error('Found multiple dcql_query in vp_token. Only one is allowed') + } + + return DcqlQuery.parse(JSON.parse(dcqlQuery[0])) } - return DcqlQuery.parse(JSON.parse(dcqlQuery[0])) -} + static getDcqlPresentationResult = (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { + hasher?: Hasher + }) => { + const dcqlPresentation = Object.fromEntries( + Object.entries(extractDcqlPresentationFromDcqlVpToken(record, opts)).map(([queryId, p]) => { + if (p.format === 'mso_mdoc') { + return [ + queryId, + { + credential_format: 'mso_mdoc', + doctype: p.vcs[0].credential.toJson().docType, + namespaces: p.vcs[0].decoded + } satisfies DcqlMdocCredential, + ] + } else if (p.format === 'vc+sd-jwt') { + return [queryId, { + credential_format: 'vc+sd-jwt', + vct: p.vcs[0].decoded.vct, + claims: p.vcs[0].decoded + } satisfies DcqlSdJwtVcCredential] + } else { + throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') + } + }), + ) -export const getDcqlPresentationResult = (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { - const dcqlPresentation = Object.fromEntries( - Object.entries(extractDcqlPresentationFromDcqlVpToken(record, opts)).map(([queryId, p]) => { - if (p.format === 'mso_mdoc') { - return [ - queryId, - { credential_format: 'mso_mdoc', doctype: p.vcs[0].credential.toJson().docType, namespaces: p.vcs[0].decoded } satisfies DcqlMdocCredential, - ] - } else if (p.format === 'vc+sd-jwt') { - return [queryId, { credential_format: 'vc+sd-jwt', vct: p.vcs[0].decoded.vct, claims: p.vcs[0].decoded } satisfies DcqlSdJwtVcCredential] - } else { - throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt') - } - }), - ) - - return DcqlPresentationResult.fromDcqlPresentation(dcqlPresentation, { dcqlQuery }) -} + return DcqlPresentationResult.fromDcqlPresentation(dcqlPresentation, { dcqlQuery }) + } -export const assertValidDcqlPresentationResult = async (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { hasher?: Hasher }) => { - const result = getDcqlPresentationResult(record, dcqlQuery, opts) - return DcqlPresentationResult.validate(result) + static assertValidDcqlPresentationResult = async (record: DcqlPresentation | string, dcqlQuery: DcqlQuery, opts: { + hasher?: Hasher + }) => { + const result = Dcql.getDcqlPresentationResult(record, dcqlQuery, opts) + return DcqlPresentationResult.validate(result) + } } diff --git a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts index 90400b3d..607d647e 100644 --- a/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts +++ b/packages/siop-oid4vp/lib/authorization-response/OpenID4VP.ts @@ -25,7 +25,7 @@ import { } from '../types' import { AuthorizationResponse } from './AuthorizationResponse' -import { assertValidDcqlPresentationResult } from './Dcql' +import { Dcql } from './Dcql' import { PresentationExchange } from './PresentationExchange' import { AuthorizationResponseOpts, @@ -96,7 +96,7 @@ export const verifyPresentations = async ( ), ) - assertValidDcqlPresentationResult(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) + await Dcql.assertValidDcqlPresentationResult(authorizationResponse.payload.vp_token as string, dcqlQuery, { hasher: verifyOpts.hasher }) if (verifiedPresentations.some((verified) => !verified)) { const message = verifiedPresentations From d8fdf44de4b398a2b23a977fa4f1313251183d77 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 14 Jan 2025 14:19:27 +0100 Subject: [PATCH 42/48] refactor: Removed potentially nulls from removeNullUndefined(...) function --- packages/siop-oid4vp/lib/request-object/Payload.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/siop-oid4vp/lib/request-object/Payload.ts b/packages/siop-oid4vp/lib/request-object/Payload.ts index 18ea2d67..395b6c63 100644 --- a/packages/siop-oid4vp/lib/request-object/Payload.ts +++ b/packages/siop-oid4vp/lib/request-object/Payload.ts @@ -47,9 +47,9 @@ export const createRequestObjectPayload = async (opts: CreateAuthorizationReques state, ...registration.payload, claims, - presentation_definition_uri: payload.presentation_definition_uri, - presentation_definition: payload.presentation_definition, - dcql_query: payload.dcql_query, + ...(payload.presentation_definition_uri && { presentation_definition_uri: payload.presentation_definition_uri }), + ...(payload.presentation_definition && { presentation_definition: payload.presentation_definition }), + ...(payload.dcql_query && { dcql_query: payload.dcql_query }), client_metadata: payload.client_metadata, iat, nbf, From 5510c53152e1166b9301ff7fe310e05cad9399a8 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 20 Jan 2025 17:05:07 +0100 Subject: [PATCH 43/48] chore: PR feedback fixes --- .../lib/__tests__/AuthenticationResponse.response.spec.ts | 2 +- packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts | 2 +- packages/siop-oid4vp/lib/authorization-request/Payload.ts | 2 +- .../lib/authorization-response/AuthorizationResponse.ts | 2 +- .../siop-oid4vp/lib/authorization-response/Payload.ts | 4 ++-- packages/siop-oid4vp/lib/authorization-response/types.ts | 4 ++-- packages/siop-oid4vp/lib/op/OP.ts | 8 ++++---- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 2 +- .../lib/schemas/AuthorizationResponseOpts.schema.ts | 6 +++--- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index 368ff707..aca7be46 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -776,7 +776,7 @@ describe('create JWT from Request JWT should', () => { alg: SigningAlgo.ES256K, }), jwtIssuer: { method: 'did', didUrl: `${mockResEntity.did}#controller`, alg: SigningAlgo.ES256K }, - dcqlQuery: { + dcqlResponse: { dcqlPresentation }, responseMode: ResponseMode.DIRECT_POST, diff --git a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts index 1c504b52..19fa4dcf 100644 --- a/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/SdJwt.spec.ts @@ -520,7 +520,7 @@ describe.skip('RP and OP interaction should', () => { } const authenticationResponseWithJWT = await op.createAuthorizationResponse(verifiedAuthReqWithJWT, { - dcqlQuery: { dcqlPresentation }, + dcqlResponse: { dcqlPresentation }, }) expect(authenticationResponseWithJWT.response.payload).toBeDefined() expect(authenticationResponseWithJWT.response.idToken).toBeDefined() diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index 8d8d47e0..5c572ad2 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -26,7 +26,7 @@ export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadO return undefined } - if (opts.vp_token.presentation_definition !== undefined && opts.vp_token.presentation_definition !== null) { + if (!opts.vp_token.presentation_definition && !opts.vp_token.presentation_definition_uri) { const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) if (discoveryResult.error) { throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) diff --git a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts index 848cea59..b290423e 100644 --- a/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts +++ b/packages/siop-oid4vp/lib/authorization-response/AuthorizationResponse.ts @@ -145,7 +145,7 @@ export class AuthorizationResponse { }, }) } else if (verifiedAuthorizationRequest.dcqlQuery) { - await Dcql.assertValidDcqlPresentationResult(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation, verifiedAuthorizationRequest.dcqlQuery, { + await Dcql.assertValidDcqlPresentationResult(responseOpts.dcqlResponse.dcqlPresentation as DcqlPresentation, verifiedAuthorizationRequest.dcqlQuery, { hasher: verifyOpts.hasher, }) } else { diff --git a/packages/siop-oid4vp/lib/authorization-response/Payload.ts b/packages/siop-oid4vp/lib/authorization-response/Payload.ts index a2bc60b9..2d2f237d 100644 --- a/packages/siop-oid4vp/lib/authorization-response/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-response/Payload.ts @@ -30,8 +30,8 @@ export const createResponsePayload = async ( } // vp tokens - if (responseOpts.dcqlQuery) { - responsePayload.vp_token = DcqlPresentation.encode(responseOpts.dcqlQuery.dcqlPresentation as DcqlPresentation) + if (responseOpts.dcqlResponse) { + responsePayload.vp_token = DcqlPresentation.encode(responseOpts.dcqlResponse.dcqlPresentation as DcqlPresentation) } else { await putPresentationSubmissionInLocation(authorizationRequest, responsePayload, responseOpts, idTokenPayload) } diff --git a/packages/siop-oid4vp/lib/authorization-response/types.ts b/packages/siop-oid4vp/lib/authorization-response/types.ts index 5f8f2b6f..620fc3b3 100644 --- a/packages/siop-oid4vp/lib/authorization-response/types.ts +++ b/packages/siop-oid4vp/lib/authorization-response/types.ts @@ -42,7 +42,7 @@ export interface AuthorizationResponseOpts { tokenType?: string refreshToken?: string presentationExchange?: PresentationExchangeResponseOpts - dcqlQuery?: DcqlQueryResponseOpts + dcqlResponse?: DcqlResponseOpts } export interface PresentationExchangeResponseOpts { @@ -61,7 +61,7 @@ export interface PresentationExchangeResponseOpts { restrictToDIDMethods?: string[] } -export interface DcqlQueryResponseOpts { +export interface DcqlResponseOpts { dcqlPresentation: Record | string> } diff --git a/packages/siop-oid4vp/lib/op/OP.ts b/packages/siop-oid4vp/lib/op/OP.ts index e4fa29fb..cafc2fa4 100644 --- a/packages/siop-oid4vp/lib/op/OP.ts +++ b/packages/siop-oid4vp/lib/op/OP.ts @@ -10,7 +10,7 @@ import { AuthorizationResponse, AuthorizationResponseOpts, AuthorizationResponseWithCorrelationId, - DcqlQueryResponseOpts, + DcqlResponseOpts, PresentationExchangeResponseOpts, } from '../authorization-response' import { encodeJsonAsURI, post } from '../helpers' @@ -107,7 +107,7 @@ export class OP { issuer?: ResponseIss | string verification?: Verification presentationExchange?: PresentationExchangeResponseOpts - dcqlQuery?: DcqlQueryResponseOpts + dcqlResponse?: DcqlResponseOpts }, ): Promise { if ( @@ -296,7 +296,7 @@ export class OP { issuer?: IIssuerId | ResponseIss audience?: string presentationExchange?: PresentationExchangeResponseOpts - dcqlQuery?: DcqlQueryResponseOpts + dcqlResponse?: DcqlResponseOpts }): AuthorizationResponseOpts { const version = opts.version ?? this._createResponseOptions.version let issuer = opts.issuer ?? this._createResponseOptions?.registration?.issuer @@ -311,7 +311,7 @@ export class OP { } // We are taking the whole presentationExchange object from a certain location const presentationExchange = opts.presentationExchange ?? this._createResponseOptions.presentationExchange - const dcqlQuery = opts.dcqlQuery ?? this._createResponseOptions.dcqlQuery + const dcqlQuery = opts.dcqlResponse ?? this._createResponseOptions.dcqlResponse const responseURI = opts.audience ?? this._createResponseOptions.responseURI return { diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 84761720..ddbb65fd 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -245,7 +245,7 @@ export class RPBuilder { true ) - // FIXME we need to find a way in the config to select dcql vs PD without breaking OID4VC-DEMO + // FIXME SPRIND-144 we need to find a way in the config to select dcql vs PD without breaking OID4VC-DEMO this._authorizationRequestPayload.presentation_definition = undefined; this._authorizationRequestPayload.presentation_definition_uri = undefined; this._requestObjectPayload.presentation_definition = undefined; diff --git a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts index 1478d7b7..c16925a4 100644 --- a/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts +++ b/packages/siop-oid4vp/lib/schemas/AuthorizationResponseOpts.schema.ts @@ -53,8 +53,8 @@ export const AuthorizationResponseOptsSchemaObj = { "presentationExchange": { "$ref": "#/definitions/PresentationExchangeResponseOpts" }, - "dcqlQuery": { - "$ref": "#/definitions/DcqlQueryResponseOpts" + "dcqlResponse": { + "$ref": "#/definitions/DcqlResponseOpts" } }, "required": [ @@ -2339,7 +2339,7 @@ export const AuthorizationResponseOptsSchemaObj = { "token_response" ] }, - "DcqlQueryResponseOpts": { + "DcqlResponseOpts": { "type": "object", "properties": { "dcqlPresentation": { From fa56bcc7091d8389f43cce45a114eb1fd87221df Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 20 Jan 2025 17:06:13 +0100 Subject: [PATCH 44/48] chore: lockfile --- pnpm-lock.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fecd8fd..9991ff9a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10022,7 +10022,7 @@ snapshots: '@digitalcredentials/bnid@2.1.2(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1))': dependencies: '@digitalcredentials/base58-universal': 1.0.1 - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) yargs: 15.4.1 transitivePeerDependencies: - react-native @@ -11892,7 +11892,7 @@ snapshots: webcrypto-shim: 0.1.7 optionalDependencies: expo: 48.0.21(@babel/core@7.26.0)(encoding@0.1.13) - react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)) + react-native-securerandom: 1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)) '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': dependencies: @@ -18230,7 +18230,7 @@ snapshots: react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) optional: true - react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(encoding@0.1.13)(react@18.3.1)): + react-native-securerandom@1.0.1(react-native@0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1)): dependencies: base64-js: 1.5.1 react-native: 0.71.19(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(encoding@0.1.13)(react@18.3.1) From 2180e7fb420ea71bb1ac56b48fb82d541fde439a Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 21 Jan 2025 10:25:54 +0100 Subject: [PATCH 45/48] chore: reverted definitionVersionDiscovery --- packages/siop-oid4vp/lib/authorization-request/Payload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index 5c572ad2..bd0d4591 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -26,7 +26,7 @@ export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadO return undefined } - if (!opts.vp_token.presentation_definition && !opts.vp_token.presentation_definition_uri) { + if (opts.vp_token.presentation_definition) { const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) if (discoveryResult.error) { throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) From 9069e270188a66267ef329cecf24ea9a00c9f36e Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 21 Jan 2025 11:29:31 +0100 Subject: [PATCH 46/48] chore: added comments in CI --- .github/workflows/build-test-on-pr.yml | 2 +- .github/workflows/build-test-publish-on-push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test-on-pr.yml b/.github/workflows/build-test-on-pr.yml index 5bfb7892..967279a8 100644 --- a/.github/workflows/build-test-on-pr.yml +++ b/.github/workflows/build-test-on-pr.yml @@ -25,7 +25,7 @@ jobs: node-version: '20.x' - uses: pnpm/action-setup@v4 with: - version: 9.15.3 + version: 9.15.3 # TODO remove later, we are temporary dealing with a broken pnpm version in the CI container - run: pnpm install - run: pnpm build - name: run CI tests diff --git a/.github/workflows/build-test-publish-on-push.yml b/.github/workflows/build-test-publish-on-push.yml index 5ee72570..216bcc79 100644 --- a/.github/workflows/build-test-publish-on-push.yml +++ b/.github/workflows/build-test-publish-on-push.yml @@ -39,7 +39,7 @@ jobs: node-version: '20.x' - uses: pnpm/action-setup@v4 with: - version: 9.15.3 + version: 9.15.3 # TODO remove later, we are temporary dealing with a broken pnpm version in the CI container - run: pnpm install - run: pnpm build - name: run integration tests From 19382fa66e9538a9428f797ea7506eaa7da3d263 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 21 Jan 2025 11:32:23 +0100 Subject: [PATCH 47/48] chore: removed commented out code --- .../lib/__tests__/AuthenticationResponse.response.spec.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts index aca7be46..381bf698 100644 --- a/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/AuthenticationResponse.response.spec.ts @@ -465,9 +465,6 @@ describe('create JWT from Request JWT should', () => { } const requestObject = await RequestObject.fromOpts(requestOpts) - /* console.log( - JSON.stringify(await AuthenticationResponse.createJWTFromRequestJWT(requestWithJWT.jwt, responseOpts, verifyOpts)) - );*/ const jwt = await requestObject.toJwt() if (!jwt) throw new Error('JWT is undefined') const authorizationRequest = await AuthorizationResponse.fromRequestObject(jwt, responseOpts, verifyOpts) @@ -783,9 +780,6 @@ describe('create JWT from Request JWT should', () => { } const requestObject = await RequestObject.fromOpts(requestOpts) - /* console.log( - JSON.stringify(await AuthenticationResponse.createJWTFromRequestJWT(requestWithJWT.jwt, responseOpts, verifyOpts)) - );*/ const jwt = await requestObject.toJwt() if (!jwt) throw new Error('JWT is undefined') const authorizationRequest = await AuthorizationResponse.fromRequestObject(jwt, responseOpts, verifyOpts) From 44db1196100f12a14ed742b88102a7125d372aca Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 23 Jan 2025 10:00:36 +0100 Subject: [PATCH 48/48] chore: fixed definitionVersionDiscovery handling --- .../lib/authorization-request/Payload.ts | 18 +++++++++++------- .../siop-oid4vp/lib/request-object/Payload.ts | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/siop-oid4vp/lib/authorization-request/Payload.ts b/packages/siop-oid4vp/lib/authorization-request/Payload.ts index bd0d4591..1a41ba5d 100644 --- a/packages/siop-oid4vp/lib/authorization-request/Payload.ts +++ b/packages/siop-oid4vp/lib/authorization-request/Payload.ts @@ -1,6 +1,6 @@ import { PEX } from '@sphereon/pex' -import { getNonce, removeNullUndefined } from '../helpers' +import { getNonce, getWithUrl, removeNullUndefined } from '../helpers' import { RequestObject } from '../request-object' import { isTarget, isTargetOrNoTargets } from '../rp/Opts' import { RPRegistrationMetadataPayloadSchema } from '../schemas' @@ -11,13 +11,13 @@ import { PassBy, RPRegistrationMetadataPayload, SIOPErrors, - SupportedVersion, + SupportedVersion } from '../types' import { createRequestRegistration } from './RequestRegistration' import { ClaimPayloadOptsVID1, CreateAuthorizationRequestOpts, PropertyTarget } from './types' -export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadOptsVID1): ClaimPayloadVID1 => { +export const createPresentationDefinitionClaimsProperties = async (opts: ClaimPayloadOptsVID1): Promise => { if ( !opts || !opts.vp_token || @@ -26,10 +26,14 @@ export const createPresentationDefinitionClaimsProperties = (opts: ClaimPayloadO return undefined } - if (opts.vp_token.presentation_definition) { - const discoveryResult = PEX.definitionVersionDiscovery(opts.vp_token.presentation_definition) + let presentationDef = opts.vp_token.presentation_definition + if (!presentationDef && opts.vp_token.presentation_definition_uri) { + presentationDef = await getWithUrl(opts.vp_token.presentation_definition_uri, false) + } + if (presentationDef) { + const discoveryResult = PEX.definitionVersionDiscovery(presentationDef) if (discoveryResult.error) { - throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID) + return Promise.reject(new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID)) } } @@ -55,7 +59,7 @@ export const createAuthorizationRequestPayload = async ( // TODO: if opts['registration] throw Error to get rid of test code using that key const clientMetadata = opts['registration'] ?? (opts.clientMetadata as ClientMetadataOpts) const registration = await createRequestRegistration(clientMetadata, opts) - const claims = opts.version >= SupportedVersion.SIOPv2_ID1 ? opts.payload.claims : createPresentationDefinitionClaimsProperties(opts.payload.claims) + const claims = opts.version >= SupportedVersion.SIOPv2_ID1 ? opts.payload.claims : await createPresentationDefinitionClaimsProperties(opts.payload.claims) const isRequestTarget = isTargetOrNoTargets(PropertyTarget.AUTHORIZATION_REQUEST, opts.requestObject.targets) const isRequestByValue = opts.requestObject.passBy === PassBy.VALUE diff --git a/packages/siop-oid4vp/lib/request-object/Payload.ts b/packages/siop-oid4vp/lib/request-object/Payload.ts index 395b6c63..408d8575 100644 --- a/packages/siop-oid4vp/lib/request-object/Payload.ts +++ b/packages/siop-oid4vp/lib/request-object/Payload.ts @@ -18,7 +18,7 @@ export const createRequestObjectPayload = async (opts: CreateAuthorizationReques const state = getState(payload.state) const registration = await createRequestRegistration(opts.clientMetadata, opts) - const claims = createPresentationDefinitionClaimsProperties(payload.claims) + const claims = await createPresentationDefinitionClaimsProperties(payload.claims) const metadataKey = opts.version >= SupportedVersion.SIOPv2_D11.valueOf() ? 'client_metadata' : 'registration' const clientId = payload.client_id ?? registration.payload[metadataKey]?.client_id