@sphereon/ssi-sdk.vc-status-list 0.34.1-next.3 → 0.34.1-next.322

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.
@@ -1,11 +1,11 @@
1
1
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
2
2
  import {
3
+ type CredentialProofFormat,
3
4
  type ICredential,
4
5
  type ICredentialStatus,
5
6
  type IIssuer,
6
7
  type IVerifiableCredential,
7
8
  type OrPromise,
8
- type CredentialProofFormat,
9
9
  type StatusListCredential,
10
10
  StatusListCredentialIdMode,
11
11
  StatusListDriverType,
@@ -13,19 +13,15 @@ import {
13
13
  StatusListType,
14
14
  type StatusPurpose2021,
15
15
  } from '@sphereon/ssi-types'
16
- import type {
17
- CredentialPayload,
18
- IAgentContext,
19
- ICredentialIssuer,
20
- ICredentialPlugin,
21
- ICredentialVerifier,
22
- IKeyManager,
23
- IPluginMethodMap,
24
- } from '@veramo/core'
16
+ import type { CredentialPayload, IAgentContext, ICredentialIssuer, ICredentialVerifier, IKeyManager, IPluginMethodMap } from '@veramo/core'
25
17
  import { DataSource } from 'typeorm'
26
18
  import type { BitsPerStatus } from '@sd-jwt/jwt-status-list'
27
19
  import type { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'
28
20
  import type { StatusListOpts } from '@sphereon/oid4vci-common'
21
+ import { BitstringStatusPurpose } from '@4sure-tech/vc-bitstring-status-lists'
22
+ import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
23
+ import { IExtractedCredentialDetails } from '../impl/IStatusList'
24
+ import { BitstringStatusListArgs, IStatusListEntity } from '@sphereon/ssi-sdk.data-store'
29
25
 
30
26
  export enum StatusOAuth {
31
27
  Valid = 0,
@@ -45,7 +41,7 @@ export type StatusList2021Args = {
45
41
  }
46
42
 
47
43
  export type OAuthStatusListArgs = {
48
- bitsPerStatus?: BitsPerStatus
44
+ bitsPerStatus: BitsPerStatus
49
45
  expiresAt?: Date
50
46
  }
51
47
 
@@ -59,6 +55,7 @@ export type BaseCreateNewStatusListArgs = {
59
55
  keyRef?: string
60
56
  statusList2021?: StatusList2021Args
61
57
  oauthStatusList?: OAuthStatusListArgs
58
+ bitstringStatusList?: BitstringStatusListArgs
62
59
  driverType?: StatusListDriverType
63
60
  }
64
61
 
@@ -71,10 +68,18 @@ export type UpdateOAuthStatusListArgs = {
71
68
  expiresAt?: Date
72
69
  }
73
70
 
71
+ export type UpdateBitstringStatusListArgs = {
72
+ statusPurpose: BitstringStatusPurpose
73
+ bitsPerStatus: number
74
+ validFrom?: Date
75
+ validUntil?: Date
76
+ ttl?: number
77
+ }
78
+
74
79
  export interface UpdateStatusListFromEncodedListArgs {
75
80
  type?: StatusListType
76
81
  statusListIndex: number | string
77
- value: boolean
82
+ value: number
78
83
  proofFormat?: CredentialProofFormat
79
84
  keyRef?: string
80
85
  correlationId?: string
@@ -83,6 +88,7 @@ export interface UpdateStatusListFromEncodedListArgs {
83
88
  id: string
84
89
  statusList2021?: UpdateStatusList2021Args
85
90
  oauthStatusList?: UpdateOAuthStatusListArgs
91
+ bitstringStatusList?: UpdateBitstringStatusListArgs
86
92
  }
87
93
 
88
94
  export interface UpdateStatusListFromStatusListCredentialArgs {
@@ -93,31 +99,33 @@ export interface UpdateStatusListFromStatusListCredentialArgs {
93
99
  }
94
100
 
95
101
  export interface StatusListResult {
102
+ id: string
96
103
  encodedList: string
97
- statusListCredential: StatusListCredential
98
- length: number
104
+ issuer: string | IIssuer
99
105
  type: StatusListType
100
106
  proofFormat: CredentialProofFormat
101
- id: string
107
+ length: number
108
+ statusListCredential: StatusListCredential
102
109
  statuslistContentType: string
103
- issuer: string | IIssuer
104
- statusList2021?: StatusList2021Details
105
- oauthStatusList?: OAuthStatusDetails
106
-
107
- // These cannot be deduced from the VC, so they are present when callers pass in these values as params
108
110
  correlationId?: string
109
111
  driverType?: StatusListDriverType
110
- credentialIdMode?: StatusListCredentialIdMode
111
- }
112
-
113
- interface StatusList2021Details {
114
- indexingDirection: StatusListIndexingDirection
115
- statusPurpose?: StatusPurpose2021
116
- }
117
112
 
118
- interface OAuthStatusDetails {
119
- bitsPerStatus?: BitsPerStatus
120
- expiresAt?: Date
113
+ statusList2021?: {
114
+ indexingDirection: StatusListIndexingDirection
115
+ statusPurpose: StatusPurpose2021
116
+ credentialIdMode: StatusListCredentialIdMode
117
+ }
118
+ oauthStatusList?: {
119
+ bitsPerStatus: number
120
+ expiresAt?: Date
121
+ }
122
+ bitstringStatusList?: {
123
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
124
+ bitsPerStatus?: number
125
+ validFrom?: Date
126
+ validUntil?: Date
127
+ ttl?: number
128
+ }
121
129
  }
122
130
 
123
131
  export interface StatusList2021EntryCredentialStatus extends ICredentialStatus {
@@ -154,12 +162,14 @@ export interface CreateStatusListArgs {
154
162
  length?: number
155
163
  statusList2021?: StatusList2021Args
156
164
  oauthStatusList?: OAuthStatusListArgs
165
+ bitstringStatusList?: BitstringStatusListArgs
157
166
  }
158
167
 
159
168
  export interface UpdateStatusListIndexArgs {
160
169
  statusListCredential: StatusListCredential // | CompactJWT
161
170
  statusListIndex: number | string
162
171
  value: number | Status2021 | StatusOAuth
172
+ bitsPerStatus?: number
163
173
  keyRef?: string
164
174
  expiresAt?: Date
165
175
  }
@@ -167,14 +177,27 @@ export interface UpdateStatusListIndexArgs {
167
177
  export interface CheckStatusIndexArgs {
168
178
  statusListCredential: StatusListCredential // | CompactJWT
169
179
  statusListIndex: string | number
180
+ bitsPerStatus?: number
170
181
  }
171
182
 
172
- export interface ToStatusListDetailsArgs {
173
- statusListPayload: StatusListCredential
183
+ // For the CREATE and READ contexts
184
+ export interface IToDetailsFromCredentialArgs {
185
+ // The source credential we are converting
186
+ statusListCredential: StatusListCredential
187
+
188
+ // The required metadata that is NOT in the credential itself
189
+ statusListType: StatusListType
190
+ bitsPerStatus?: number
174
191
  correlationId?: string
175
192
  driverType?: StatusListDriverType
176
193
  }
177
194
 
195
+ // For the UPDATE context
196
+ export interface IMergeDetailsWithEntityArgs {
197
+ extractedDetails: IExtractedCredentialDetails
198
+ statusListEntity: IStatusListEntity
199
+ }
200
+
178
201
  /**
179
202
  * The interface definition for a plugin that can add statuslist info to a credential
180
203
  *
@@ -260,5 +283,5 @@ export type SignedStatusListData = {
260
283
  encodedList: string
261
284
  }
262
285
 
263
- export type IRequiredPlugins = ICredentialPlugin & IIdentifierResolution
264
- export type IRequiredContext = IAgentContext<ICredentialIssuer & ICredentialVerifier & IIdentifierResolution & IKeyManager & ICredentialPlugin>
286
+ export type IRequiredPlugins = IVcdmCredentialPlugin & IIdentifierResolution
287
+ export type IRequiredContext = IAgentContext<ICredentialIssuer & ICredentialVerifier & IIdentifierResolution & IKeyManager & IVcdmCredentialPlugin>
package/src/utils.ts CHANGED
@@ -11,7 +11,7 @@ import { jwtDecode } from 'jwt-decode'
11
11
 
12
12
  export function getAssertedStatusListType(type?: StatusListType) {
13
13
  const assertedType = type ?? StatusListType.StatusList2021
14
- if (![StatusListType.StatusList2021, StatusListType.OAuthStatusList].includes(assertedType)) {
14
+ if (![StatusListType.StatusList2021, StatusListType.OAuthStatusList, StatusListType.BitstringStatusList].includes(assertedType)) {
15
15
  throw Error(`StatusList type ${assertedType} is not supported (yet)`)
16
16
  }
17
17
  return assertedType
@@ -39,8 +39,9 @@ export function getAssertedProperty<T extends object>(propertyName: string, obj:
39
39
  }
40
40
 
41
41
  const ValidProofTypeMap = new Map<StatusListType, CredentialProofFormat[]>([
42
- [StatusListType.StatusList2021, ['jwt', 'lds', 'EthereumEip712Signature2021']],
42
+ [StatusListType.StatusList2021, ['jwt', 'lds']],
43
43
  [StatusListType.OAuthStatusList, ['jwt', 'cbor']],
44
+ [StatusListType.BitstringStatusList, ['lds', 'vc+jwt']],
44
45
  ])
45
46
 
46
47
  export function assertValidProofType(type: StatusListType, proofFormat: CredentialProofFormat) {
@@ -52,31 +53,60 @@ export function assertValidProofType(type: StatusListType, proofFormat: Credenti
52
53
 
53
54
  export function determineStatusListType(credential: StatusListCredential): StatusListType {
54
55
  const proofFormat = determineProofFormat(credential)
56
+
55
57
  switch (proofFormat) {
56
58
  case 'jwt':
57
- const payload: StatusListCredential = jwtDecode(credential as string)
58
- const keys = Object.keys(payload)
59
- if (keys.includes('status_list')) {
60
- return StatusListType.OAuthStatusList
61
- } else if (keys.includes('vc')) {
62
- return StatusListType.StatusList2021
63
- }
64
- break
59
+ return determineJwtStatusListType(credential as string)
65
60
  case 'lds':
66
- const uniform = CredentialMapper.toUniformCredential(credential)
67
- const type = uniform.type.find((t) => {
68
- return Object.values(StatusListType).some((statusType) => t.includes(statusType))
69
- })
70
- if (!type) {
71
- throw new Error('Invalid status list credential type')
72
- }
73
- return type.replace('Credential', '') as StatusListType
74
-
61
+ return determineLdsStatusListType(credential)
75
62
  case 'cbor':
76
63
  return StatusListType.OAuthStatusList
64
+ default:
65
+ throw new Error('Cannot determine status list type from credential payload')
66
+ }
67
+ }
68
+
69
+ function determineJwtStatusListType(credential: string): StatusListType {
70
+ const payload: any = jwtDecode(credential)
71
+
72
+ // OAuth status list format
73
+ if ('status_list' in payload) {
74
+ return StatusListType.OAuthStatusList
75
+ }
76
+
77
+ // Direct credential subject
78
+ if ('credentialSubject' in payload) {
79
+ return getStatusListTypeFromSubject(payload.credentialSubject)
80
+ }
81
+
82
+ // Wrapped VC format
83
+ if ('vc' in payload && 'credentialSubject' in payload.vc) {
84
+ return getStatusListTypeFromSubject(payload.vc.credentialSubject)
85
+ }
86
+
87
+ throw new Error('Invalid status list credential: credentialSubject not found')
88
+ }
89
+
90
+ function determineLdsStatusListType(credential: StatusListCredential): StatusListType {
91
+ const uniform = CredentialMapper.toUniformCredential(credential)
92
+ const statusListType = uniform.type.find((type) => Object.values(StatusListType).some((statusType) => type.includes(statusType)))
93
+
94
+ if (!statusListType) {
95
+ throw new Error('Invalid status list credential type')
77
96
  }
78
97
 
79
- throw new Error('Cannot determine status list type from credential payload')
98
+ return statusListType.replace('Credential', '') as StatusListType
99
+ }
100
+
101
+ function getStatusListTypeFromSubject(credentialSubject: any): StatusListType {
102
+ switch (credentialSubject.type) {
103
+ case 'StatusList2021':
104
+ return StatusListType.StatusList2021
105
+ case 'BitstringStatusList':
106
+ return StatusListType.BitstringStatusList
107
+ default:
108
+ throw new Error(`Unknown credential subject type: ${credentialSubject.type}`)
109
+ }
80
110
  }
81
111
 
82
112
  export function determineProofFormat(credential: StatusListCredential): CredentialProofFormat {
@@ -93,3 +123,35 @@ export function determineProofFormat(credential: StatusListCredential): Credenti
93
123
  throw Error('Cannot determine credential payload type')
94
124
  }
95
125
  }
126
+
127
+ /**
128
+ * Ensures a value is converted to a Date object if it's a valid date string,
129
+ * otherwise returns the original value or undefined
130
+ *
131
+ * @param value - The value to convert to Date (can be Date, string, or undefined)
132
+ * @returns Date object, undefined, or the original value if conversion fails
133
+ */
134
+ export function ensureDate(value: Date | string | undefined): Date | undefined {
135
+ if (value === undefined || value === null) {
136
+ return undefined
137
+ }
138
+
139
+ if (value instanceof Date) {
140
+ return value
141
+ }
142
+
143
+ if (typeof value === 'string') {
144
+ if (value.trim() === '') {
145
+ return undefined
146
+ }
147
+
148
+ const date = new Date(value)
149
+ // Check if the date is valid
150
+ if (isNaN(date.getTime())) {
151
+ return undefined
152
+ }
153
+ return date
154
+ }
155
+
156
+ return undefined
157
+ }