@sphereon/ssi-sdk.siopv2-oid4vp-op-auth 0.32.1-next.20 → 0.32.1-next.287

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agent/DidAuthSiopOpAuthenticator.d.ts +8 -3
  2. package/dist/agent/DidAuthSiopOpAuthenticator.d.ts.map +1 -1
  3. package/dist/agent/DidAuthSiopOpAuthenticator.js +105 -35
  4. package/dist/agent/DidAuthSiopOpAuthenticator.js.map +1 -1
  5. package/dist/services/Siopv2MachineService.d.ts +5 -0
  6. package/dist/services/Siopv2MachineService.d.ts.map +1 -1
  7. package/dist/services/Siopv2MachineService.js +112 -14
  8. package/dist/services/Siopv2MachineService.js.map +1 -1
  9. package/dist/session/OID4VP.d.ts +4 -4
  10. package/dist/session/OID4VP.d.ts.map +1 -1
  11. package/dist/session/OID4VP.js +2 -1
  12. package/dist/session/OID4VP.js.map +1 -1
  13. package/dist/session/OpSession.d.ts.map +1 -1
  14. package/dist/session/OpSession.js +3 -3
  15. package/dist/session/OpSession.js.map +1 -1
  16. package/dist/types/IDidAuthSiopOpAuthenticator.d.ts +12 -7
  17. package/dist/types/IDidAuthSiopOpAuthenticator.d.ts.map +1 -1
  18. package/dist/types/IDidAuthSiopOpAuthenticator.js.map +1 -1
  19. package/dist/types/machine/index.d.ts +1 -0
  20. package/dist/types/machine/index.d.ts.map +1 -1
  21. package/dist/types/machine/index.js.map +1 -1
  22. package/dist/types/siop-service/index.d.ts +22 -5
  23. package/dist/types/siop-service/index.d.ts.map +1 -1
  24. package/dist/types/siop-service/index.js.map +1 -1
  25. package/dist/utils/CredentialUtils.d.ts +23 -0
  26. package/dist/utils/CredentialUtils.d.ts.map +1 -0
  27. package/dist/utils/CredentialUtils.js +65 -0
  28. package/dist/utils/CredentialUtils.js.map +1 -0
  29. package/dist/utils/dcql.d.ts +5 -0
  30. package/dist/utils/dcql.d.ts.map +1 -0
  31. package/dist/utils/dcql.js +37 -0
  32. package/dist/utils/dcql.js.map +1 -0
  33. package/package.json +26 -23
  34. package/src/agent/DidAuthSiopOpAuthenticator.ts +132 -49
  35. package/src/services/Siopv2MachineService.ts +132 -19
  36. package/src/session/OID4VP.ts +8 -8
  37. package/src/session/OpSession.ts +7 -5
  38. package/src/types/IDidAuthSiopOpAuthenticator.ts +21 -7
  39. package/src/types/machine/index.ts +1 -0
  40. package/src/types/siop-service/index.ts +25 -5
  41. package/src/utils/CredentialUtils.ts +71 -0
  42. package/src/utils/dcql.ts +36 -0
@@ -20,7 +20,7 @@ import { encodeBase64url } from '@sphereon/ssi-sdk.core'
20
20
  import {
21
21
  CompactSdJwtVc,
22
22
  CredentialMapper,
23
- Hasher,
23
+ HasherSync,
24
24
  OriginalVerifiableCredential,
25
25
  parseDid,
26
26
  PresentationSubmission,
@@ -240,7 +240,7 @@ export class OpSession {
240
240
  private createPresentationVerificationCallback(context: IRequiredContext) {
241
241
  async function presentationVerificationCallback(
242
242
  args: W3CVerifiablePresentation | CompactSdJwtVc,
243
- presentationSubmission: PresentationSubmission,
243
+ presentationSubmission?: PresentationSubmission,
244
244
  ): Promise<PresentationVerificationResult> {
245
245
  let result: IVerifyResult
246
246
  if (CredentialMapper.isSdJwtEncoded(args)) {
@@ -293,8 +293,8 @@ export class OpSession {
293
293
  .jwtEncryptJweCompactJwt({
294
294
  recipientKey,
295
295
  protectedHeader: {},
296
- alg: requestObjectPayload.client_metadata.authorization_encrypted_response_alg as JweAlg | undefined ?? 'ECDH-ES',
297
- enc: requestObjectPayload.client_metadata.authorization_encrypted_response_enc as JweEnc | undefined ?? 'A256GCM',
296
+ alg: (requestObjectPayload.client_metadata.authorization_encrypted_response_alg as JweAlg | undefined) ?? 'ECDH-ES',
297
+ enc: (requestObjectPayload.client_metadata.authorization_encrypted_response_enc as JweEnc | undefined) ?? 'A256GCM',
298
298
  apv: encodeBase64url(opts.requestObjectPayload.nonce),
299
299
  apu: encodeBase64url(v4()),
300
300
  payload: authResponse,
@@ -360,12 +360,14 @@ export class OpSession {
360
360
  const responseOpts = {
361
361
  verification,
362
362
  issuer,
363
+ ...(args.isFirstParty && { isFirstParty: args.isFirstParty }),
363
364
  ...(args.verifiablePresentations && {
364
365
  presentationExchange: {
365
366
  verifiablePresentations,
366
367
  presentationSubmission: args.presentationSubmission,
367
368
  } as PresentationExchangeResponseOpts,
368
369
  }),
370
+ dcqlQuery: args.dcqlResponse,
369
371
  }
370
372
 
371
373
  const authResponse = await op.createAuthorizationResponse(request, responseOpts)
@@ -378,7 +380,7 @@ export class OpSession {
378
380
  }
379
381
  }
380
382
 
381
- private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[], hasher?: Hasher) {
383
+ private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[], hasher?: HasherSync) {
382
384
  return verifiablePresentations.reduce((sum, vp) => {
383
385
  if (CredentialMapper.isMsoMdocDecodedPresentation(vp) || CredentialMapper.isMsoMdocOid4VPEncoded(vp)) {
384
386
  return sum + 1
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DcqlResponseOpts,
2
3
  PresentationDefinitionWithLocation,
3
4
  PresentationSignCallback,
4
5
  ResponseMode,
@@ -18,7 +19,7 @@ import { ICredentialStore, UniqueDigitalCredential } from '@sphereon/ssi-sdk.cre
18
19
  import { Party } from '@sphereon/ssi-sdk.data-store'
19
20
  import { IPDManager } from '@sphereon/ssi-sdk.pd-manager'
20
21
  import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
21
- import { Hasher, OriginalVerifiableCredential, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types'
22
+ import { HasherSync, OriginalVerifiableCredential, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types'
22
23
  import { VerifyCallback } from '@sphereon/wellknown-dids-client'
23
24
  import {
24
25
  IAgentContext,
@@ -122,7 +123,9 @@ export interface IOpsSendSiopAuthorizationResponseArgs {
122
123
  // verifiedAuthorizationRequest: VerifiedAuthorizationRequest
123
124
  presentationSubmission?: PresentationSubmission
124
125
  verifiablePresentations?: W3CVerifiablePresentation[]
125
- hasher?: Hasher
126
+ dcqlResponse?: DcqlResponseOpts
127
+ hasher?: HasherSync
128
+ isFirstParty?: boolean
126
129
  }
127
130
 
128
131
  export enum events {
@@ -159,7 +162,7 @@ export interface IOPOptions {
159
162
  presentationSignCallback?: PresentationSignCallback
160
163
 
161
164
  resolveOpts?: ResolveOpts
162
- hasher?: Hasher
165
+ hasher?: HasherSync
163
166
  }
164
167
 
165
168
  /*
@@ -182,19 +185,30 @@ export interface VerifiablePresentationWithDefinition extends VerifiablePresenta
182
185
 
183
186
  export interface IOpSessionGetOID4VPArgs {
184
187
  allIdentifiers?: string[]
185
- hasher?: Hasher
188
+ hasher?: HasherSync
186
189
  }
187
190
 
188
191
  export interface IOID4VPArgs {
189
192
  session: OpSession
190
193
  allIdentifiers?: string[]
191
- hasher?: Hasher
194
+ hasher?: HasherSync
192
195
  }
193
196
 
194
197
  export interface IGetPresentationExchangeArgs {
195
198
  verifiableCredentials: OriginalVerifiableCredential[]
196
199
  allIdentifiers?: string[]
197
- hasher?: Hasher
198
- }
200
+ hasher?: HasherSync
201
+ }
202
+
203
+ // It was added here because it's not exported from DCQL anymore
204
+ export type Json =
205
+ | string
206
+ | number
207
+ | boolean
208
+ | null
209
+ | {
210
+ [key: string]: Json
211
+ }
212
+ | Json[]
199
213
 
200
214
  export const DEFAULT_JWT_PROOF_TYPE = 'JwtProof2020'
@@ -18,6 +18,7 @@ export type Siopv2MachineContext = {
18
18
  contactAlias: string
19
19
  selectableCredentialsMap?: SelectableCredentialsMap
20
20
  selectedCredentials: Array<UniqueDigitalCredential>
21
+ isFirstParty?: boolean
21
22
  error?: ErrorDetails
22
23
  }
23
24
 
@@ -1,4 +1,9 @@
1
- import { PresentationDefinitionWithLocation, RPRegistrationMetadataPayload } from '@sphereon/did-auth-siop'
1
+ import {
2
+ PresentationDefinitionWithLocation,
3
+ PresentationSignCallback,
4
+ RPRegistrationMetadataPayload,
5
+ VerifiedAuthorizationRequest,
6
+ } from '@sphereon/did-auth-siop'
2
7
  import { IIdentifierResolution, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
3
8
  import { IContactManager } from '@sphereon/ssi-sdk.contact-manager'
4
9
  import { ICredentialStore, UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
@@ -7,10 +12,15 @@ import { IIssuanceBranding } from '@sphereon/ssi-sdk.issuance-branding'
7
12
  import { IAgentContext, IDIDManager, IIdentifier, IResolver } from '@veramo/core'
8
13
  import { IDidAuthSiopOpAuthenticator } from '../IDidAuthSiopOpAuthenticator'
9
14
  import { Siopv2MachineContext, Siopv2MachineInterpreter, Siopv2MachineState } from '../machine'
15
+ import { DcqlQuery } from 'dcql'
16
+ import { HasherSync } from '@sphereon/ssi-types'
10
17
 
11
18
  export type DidAuthSiopOpAuthenticatorOptions = {
19
+ presentationSignCallback?: PresentationSignCallback
20
+ customApprovals?: Record<string, (verifiedAuthorizationRequest: VerifiedAuthorizationRequest, sessionId: string) => Promise<void>>
12
21
  onContactIdentityCreated?: (args: OnContactIdentityCreatedArgs) => Promise<void>
13
22
  onIdentifierCreated?: (args: OnIdentifierCreatedArgs) => Promise<void>
23
+ hasher?: HasherSync
14
24
  }
15
25
 
16
26
  export type GetMachineArgs = {
@@ -19,12 +29,21 @@ export type GetMachineArgs = {
19
29
  stateNavigationListener?: (siopv2Machine: Siopv2MachineInterpreter, state: Siopv2MachineState, navigation?: any) => Promise<void>
20
30
  }
21
31
 
22
- export type CreateConfigArgs = Pick<Siopv2MachineContext, 'url'>
32
+ export type CreateConfigArgs = { url: string }
23
33
  export type CreateConfigResult = Omit<DidAuthConfig, 'stateId' | 'idOpts'>
24
- export type GetSiopRequestArgs = Pick<Siopv2MachineContext, 'didAuthConfig' | 'url'>
34
+ export type GetSiopRequestArgs = { didAuthConfig?: Omit<DidAuthConfig, 'identifier'>; url: string }
35
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
25
36
  export type RetrieveContactArgs = Pick<Siopv2MachineContext, 'url' | 'authorizationRequestData'>
37
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
26
38
  export type AddIdentityArgs = Pick<Siopv2MachineContext, 'contact' | 'authorizationRequestData'>
27
- export type SendResponseArgs = Pick<Siopv2MachineContext, 'didAuthConfig' | 'authorizationRequestData' | 'selectedCredentials' | 'idOpts'>
39
+ export type SendResponseArgs = {
40
+ didAuthConfig?: Omit<DidAuthConfig, 'identifier'>
41
+ authorizationRequestData?: Siopv2AuthorizationRequestData
42
+ selectedCredentials: Array<UniqueDigitalCredential>
43
+ idOpts?: ManagedIdentifierOptsOrResult
44
+ isFirstParty?: boolean
45
+ }
46
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
28
47
  export type GetSelectableCredentialsArgs = Pick<Siopv2MachineContext, 'authorizationRequestData'>
29
48
 
30
49
  export enum Siopv2HolderEvent {
@@ -38,7 +57,7 @@ export enum SupportedLanguage {
38
57
  }
39
58
 
40
59
  export type Siopv2AuthorizationResponseData = {
41
- body?: string
60
+ body?: string | Record<string, any>
42
61
  url?: string
43
62
  queryParams?: Record<string, any>
44
63
  }
@@ -51,6 +70,7 @@ export type Siopv2AuthorizationRequestData = {
51
70
  uri?: URL
52
71
  clientId?: string
53
72
  presentationDefinitions?: PresentationDefinitionWithLocation[]
73
+ dcqlQuery?: DcqlQuery
54
74
  }
55
75
 
56
76
  export type SelectableCredentialsMap = Map<string, Array<SelectableCredential>>
@@ -0,0 +1,71 @@
1
+ import { CredentialMapper, HasherSync, ICredential, IVerifiableCredential, OriginalVerifiableCredential } from '@sphereon/ssi-types'
2
+ import { VerifiableCredential } from '@veramo/core'
3
+ import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
4
+
5
+ /**
6
+ * Return the type(s) of a VC minus the VerifiableCredential type which should always be present
7
+ * @param credential The input credential
8
+ */
9
+ export const getCredentialTypeAsString = (credential: ICredential | VerifiableCredential): string => {
10
+ if (!credential.type) {
11
+ return 'Verifiable Credential'
12
+ } else if (typeof credential.type === 'string') {
13
+ return credential.type
14
+ }
15
+ return credential.type.filter((type: string): boolean => type !== 'VerifiableCredential').join(', ')
16
+ }
17
+
18
+ /**
19
+ * Returns a Unique Verifiable Credential (with hash) as stored in Veramo, based upon matching the id of the input VC or the proof value of the input VC
20
+ * @param uniqueVCs The Unique VCs to search in
21
+ * @param searchVC The VC to search for in the unique VCs array
22
+ */
23
+ export const getMatchingUniqueDigitalCredential = (
24
+ uniqueVCs: UniqueDigitalCredential[],
25
+ searchVC: OriginalVerifiableCredential,
26
+ ): UniqueDigitalCredential | undefined => {
27
+ // Since an ID is optional in a VC according to VCDM, and we really need the matches, we have a fallback match on something which is guaranteed to be unique for any VC (the proof(s))
28
+ return uniqueVCs.find(
29
+ (uniqueVC: UniqueDigitalCredential) =>
30
+ (typeof searchVC !== 'string' &&
31
+ (uniqueVC.id === (<IVerifiableCredential>searchVC).id ||
32
+ (uniqueVC.originalVerifiableCredential as VerifiableCredential).proof === (<IVerifiableCredential>searchVC).proof)) ||
33
+ (typeof searchVC === 'string' && (uniqueVC.uniformVerifiableCredential as VerifiableCredential)?.proof?.jwt === searchVC) ||
34
+ // We are ignoring the signature of the sd-jwt as PEX signs the vc again and it will not match anymore with the jwt in the proof of the stored jsonld vc
35
+ (typeof searchVC === 'string' &&
36
+ CredentialMapper.isSdJwtEncoded(searchVC) &&
37
+ uniqueVC.uniformVerifiableCredential?.proof &&
38
+ 'jwt' in uniqueVC.uniformVerifiableCredential.proof &&
39
+ uniqueVC.uniformVerifiableCredential.proof.jwt?.split('.')?.slice(0, 2)?.join('.') === searchVC.split('.')?.slice(0, 2)?.join('.')),
40
+ )
41
+ }
42
+
43
+ type InputCredential = UniqueDigitalCredential | VerifiableCredential | ICredential | OriginalVerifiableCredential
44
+
45
+ /**
46
+ * Get an original verifiable credential. Maps to wrapped Verifiable Credential first, to get an original JWT as Veramo stores these with a special proof value
47
+ * @param credential The input VC
48
+ */
49
+
50
+ export const getOriginalVerifiableCredential = (credential: InputCredential): OriginalVerifiableCredential => {
51
+ if (isUniqueDigitalCredential(credential)) {
52
+ if (!credential.originalVerifiableCredential) {
53
+ throw new Error('originalVerifiableCredential is not defined in UniqueDigitalCredential')
54
+ }
55
+ return getCredentialFromProofOrWrapped(credential.originalVerifiableCredential)
56
+ }
57
+
58
+ return getCredentialFromProofOrWrapped(credential)
59
+ }
60
+
61
+ const getCredentialFromProofOrWrapped = (cred: any, hasher?: HasherSync): OriginalVerifiableCredential => {
62
+ if (typeof cred === 'object' && 'proof' in cred && 'jwt' in cred.proof && CredentialMapper.isSdJwtEncoded(cred.proof.jwt)) {
63
+ return cred.proof.jwt
64
+ }
65
+
66
+ return CredentialMapper.toWrappedVerifiableCredential(cred as OriginalVerifiableCredential, { hasher }).original
67
+ }
68
+
69
+ export const isUniqueDigitalCredential = (credential: InputCredential): credential is UniqueDigitalCredential => {
70
+ return (credential as UniqueDigitalCredential).digitalCredential !== undefined
71
+ }
@@ -0,0 +1,36 @@
1
+ import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
2
+ import { DcqlCredential, DcqlSdJwtVcCredential, DcqlW3cVcCredential } from 'dcql'
3
+ import { CredentialMapper, HasherSync, OriginalVerifiableCredential } from '@sphereon/ssi-types'
4
+ import { isUniqueDigitalCredential } from './CredentialUtils'
5
+
6
+ export function convertToDcqlCredentials(credential: UniqueDigitalCredential | OriginalVerifiableCredential, hasher?: HasherSync): DcqlCredential {
7
+ let payload
8
+ if (isUniqueDigitalCredential(credential)) {
9
+ if (!credential.originalVerifiableCredential) {
10
+ throw new Error('originalVerifiableCredential is not defined in UniqueDigitalCredential')
11
+ }
12
+ payload = CredentialMapper.decodeVerifiableCredential(credential.originalVerifiableCredential, hasher)
13
+ } else {
14
+ payload = CredentialMapper.decodeVerifiableCredential(credential as OriginalVerifiableCredential, hasher)
15
+ }
16
+
17
+ if (!payload) {
18
+ throw new Error('No payload found')
19
+ }
20
+
21
+ if ('decodedPayload' in payload && payload.decodedPayload) {
22
+ payload = payload.decodedPayload
23
+ }
24
+
25
+ if ('vct' in payload!) {
26
+ return { vct: payload.vct, claims: payload, credential_format: 'vc+sd-jwt' } satisfies DcqlSdJwtVcCredential // TODO dc+sd-jwt support?
27
+ } else if ('docType' in payload! && 'namespaces' in payload) {
28
+ // mdoc
29
+ return { docType: payload.docType, namespaces: payload.namespaces, claims: payload }
30
+ } else {
31
+ return {
32
+ claims: payload,
33
+ credential_format: 'jwt_vc_json', // TODO jwt_vc_json-ld support
34
+ } as DcqlW3cVcCredential
35
+ }
36
+ }