@sphereon/ssi-sdk.vc-status-list 0.34.0 → 0.34.1-feature.SSISDK.17.bitstring.sl.11
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.
- package/dist/index.cjs +424 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -26
- package/dist/index.d.ts +76 -26
- package/dist/index.js +425 -46
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/functions.ts +50 -14
- package/src/impl/BitstringStatusListImplementation.ts +347 -0
- package/src/impl/IStatusList.ts +66 -4
- package/src/impl/OAuthStatusList.ts +60 -18
- package/src/impl/StatusList2021.ts +47 -12
- package/src/impl/StatusListFactory.ts +2 -0
- package/src/types/BitstringStatusList.ts +4 -0
- package/src/types/index.ts +71 -22
- package/src/utils.ts +35 -2
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import type { IAgentContext, ICredentialPlugin, IKeyManager } from '@veramo/core'
|
|
2
|
-
import { type CompactJWT, type
|
|
2
|
+
import { type CompactJWT, type CredentialProofFormat, type CWT, StatusListType } from '@sphereon/ssi-types'
|
|
3
3
|
import type {
|
|
4
4
|
CheckStatusIndexArgs,
|
|
5
5
|
CreateStatusListArgs,
|
|
6
6
|
SignedStatusListData,
|
|
7
|
+
StatusListOAuthEntryCredentialStatus,
|
|
7
8
|
StatusListResult,
|
|
8
9
|
StatusOAuth,
|
|
9
10
|
ToStatusListDetailsArgs,
|
|
10
11
|
UpdateStatusListFromEncodedListArgs,
|
|
11
12
|
UpdateStatusListIndexArgs,
|
|
12
13
|
} from '../types'
|
|
13
|
-
import { determineProofFormat, getAssertedValue, getAssertedValues } from '../utils'
|
|
14
|
-
import type { IStatusList } from './IStatusList'
|
|
14
|
+
import { determineProofFormat, ensureDate, getAssertedValue, getAssertedValues } from '../utils'
|
|
15
|
+
import type { IOAuthStatusListImplementationResult, IStatusList } from './IStatusList'
|
|
15
16
|
import { StatusList } from '@sd-jwt/jwt-status-list'
|
|
16
17
|
import type { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
17
18
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
18
19
|
import { createSignedJwt, decodeStatusListJWT } from './encoding/jwt'
|
|
19
20
|
import { createSignedCbor, decodeStatusListCWT } from './encoding/cbor'
|
|
21
|
+
import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, OAuthStatusListEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
20
22
|
|
|
21
23
|
type IRequiredContext = IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>
|
|
22
24
|
|
|
23
|
-
export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID"
|
|
25
|
+
export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
|
|
24
26
|
export const DEFAULT_LIST_LENGTH = 250000
|
|
25
27
|
export const DEFAULT_PROOF_FORMAT = 'jwt' as CredentialProofFormat
|
|
26
28
|
|
|
@@ -32,7 +34,8 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
32
34
|
|
|
33
35
|
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
|
|
34
36
|
const { issuer, id, oauthStatusList, keyRef } = args
|
|
35
|
-
const { bitsPerStatus
|
|
37
|
+
const { bitsPerStatus } = oauthStatusList
|
|
38
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt)
|
|
36
39
|
const length = args.length ?? DEFAULT_LIST_LENGTH
|
|
37
40
|
const issuerString = typeof issuer === 'string' ? issuer : issuer.id
|
|
38
41
|
const correlationId = getAssertedValue('correlationId', args.correlationId)
|
|
@@ -56,7 +59,8 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
async updateStatusListIndex(args: UpdateStatusListIndexArgs, context: IRequiredContext): Promise<StatusListResult> {
|
|
59
|
-
const { statusListCredential, value,
|
|
62
|
+
const { statusListCredential, value, keyRef } = args
|
|
63
|
+
const expiresAt = ensureDate(args.expiresAt)
|
|
60
64
|
if (typeof statusListCredential !== 'string') {
|
|
61
65
|
return Promise.reject('statusListCredential in neither JWT nor CWT')
|
|
62
66
|
}
|
|
@@ -70,6 +74,10 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
70
74
|
throw new Error('Status list index out of bounds')
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
if (typeof value !== 'number') {
|
|
78
|
+
throw new Error('Status list values should be of type number')
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
statusList.setStatus(index, value)
|
|
74
82
|
const { statusListCredential: signedCredential, encodedList } = await this.createSignedStatusList(
|
|
75
83
|
proofFormat,
|
|
@@ -102,15 +110,15 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
102
110
|
throw new Error('OAuthStatusList options are required for type OAuthStatusList')
|
|
103
111
|
}
|
|
104
112
|
const { proofFormat, oauthStatusList, keyRef } = args
|
|
105
|
-
const { bitsPerStatus
|
|
113
|
+
const { bitsPerStatus } = oauthStatusList
|
|
114
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt)
|
|
106
115
|
|
|
107
116
|
const { issuer, id } = getAssertedValues(args)
|
|
108
117
|
const issuerString = typeof issuer === 'string' ? issuer : issuer.id
|
|
109
118
|
|
|
110
119
|
const listToUpdate = StatusList.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS)
|
|
111
120
|
const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
|
|
112
|
-
|
|
113
|
-
listToUpdate.setStatus(index, args.value ? 1 : 0)
|
|
121
|
+
listToUpdate.setStatus(index, args.value)
|
|
114
122
|
|
|
115
123
|
const { statusListCredential, encodedList } = await this.createSignedStatusList(
|
|
116
124
|
proofFormat ?? DEFAULT_PROOF_FORMAT,
|
|
@@ -138,10 +146,6 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
private buildContentType(proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor' | undefined) {
|
|
142
|
-
return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
|
|
143
|
-
}
|
|
144
|
-
|
|
145
149
|
async checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | StatusOAuth> {
|
|
146
150
|
const { statusListCredential, statusListIndex } = args
|
|
147
151
|
if (typeof statusListCredential !== 'string') {
|
|
@@ -153,19 +157,23 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
153
157
|
|
|
154
158
|
const index = typeof statusListIndex === 'number' ? statusListIndex : parseInt(statusListIndex)
|
|
155
159
|
if (index < 0 || index >= statusList.statusList.length) {
|
|
156
|
-
throw new Error(
|
|
160
|
+
throw new Error(`Status list index out of bounds, has ${statusList.statusList.length} items, requested ${index}`)
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
return statusList.getStatus(index)
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
|
|
166
|
+
async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult> {
|
|
163
167
|
const { statusListPayload } = args as { statusListPayload: CompactJWT | CWT }
|
|
164
168
|
const proofFormat = determineProofFormat(statusListPayload)
|
|
165
169
|
const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload)
|
|
166
170
|
const { statusList, issuer, id, exp } = decoded
|
|
167
171
|
|
|
172
|
+
const bitsPerStatus = statusList.getBitsPerStatus()
|
|
173
|
+
const expiresAt = exp ? new Date(exp * 1000) : undefined
|
|
174
|
+
|
|
168
175
|
return {
|
|
176
|
+
// Base implementation fields
|
|
169
177
|
id,
|
|
170
178
|
encodedList: statusList.compressStatusList(),
|
|
171
179
|
issuer,
|
|
@@ -174,17 +182,51 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
174
182
|
length: statusList.statusList.length,
|
|
175
183
|
statusListCredential: statusListPayload,
|
|
176
184
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
185
|
+
correlationId: args.correlationId, // FIXME these do not need to be inside the impl
|
|
186
|
+
driverType: args.driverType, // FIXME these do not need to be inside the impl
|
|
187
|
+
|
|
188
|
+
// Flattened OAuth-specific fields
|
|
189
|
+
bitsPerStatus,
|
|
190
|
+
...(expiresAt && { expiresAt }),
|
|
191
|
+
|
|
192
|
+
// Legacy nested structure for backward compatibility
|
|
177
193
|
oauthStatusList: {
|
|
178
|
-
bitsPerStatus
|
|
179
|
-
...(
|
|
194
|
+
bitsPerStatus,
|
|
195
|
+
...(expiresAt && { expiresAt }),
|
|
180
196
|
},
|
|
197
|
+
|
|
198
|
+
// Optional fields from args
|
|
181
199
|
...(args.correlationId && { correlationId: args.correlationId }),
|
|
182
200
|
...(args.driverType && { driverType: args.driverType }),
|
|
183
201
|
}
|
|
184
202
|
}
|
|
185
203
|
|
|
204
|
+
async createCredentialStatus(args: {
|
|
205
|
+
statusList: StatusListEntity
|
|
206
|
+
statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
|
|
207
|
+
statusListIndex: number
|
|
208
|
+
}): Promise<StatusListOAuthEntryCredentialStatus> {
|
|
209
|
+
const { statusList, statusListIndex } = args
|
|
210
|
+
|
|
211
|
+
// Cast to OAuthStatusListEntity to access specific properties
|
|
212
|
+
const oauthStatusList = statusList as OAuthStatusListEntity
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
216
|
+
type: 'OAuthStatusListEntry',
|
|
217
|
+
bitsPerStatus: oauthStatusList.bitsPerStatus,
|
|
218
|
+
statusListIndex: '' + statusListIndex,
|
|
219
|
+
statusListCredential: statusList.id,
|
|
220
|
+
expiresAt: oauthStatusList.expiresAt,
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private buildContentType(proofFormat: CredentialProofFormat | undefined) {
|
|
225
|
+
return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
|
|
226
|
+
}
|
|
227
|
+
|
|
186
228
|
private async createSignedStatusList(
|
|
187
|
-
proofFormat:
|
|
229
|
+
proofFormat: CredentialProofFormat,
|
|
188
230
|
context: IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
|
|
189
231
|
statusList: StatusList,
|
|
190
232
|
issuerString: string,
|
|
@@ -2,15 +2,15 @@ import type { IAgentContext, ICredentialPlugin, ProofFormat as VeramoProofFormat
|
|
|
2
2
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
3
3
|
import {
|
|
4
4
|
CredentialMapper,
|
|
5
|
+
type CredentialProofFormat,
|
|
5
6
|
DocumentFormat,
|
|
6
7
|
type IIssuer,
|
|
7
|
-
type CredentialProofFormat,
|
|
8
8
|
type StatusListCredential,
|
|
9
9
|
StatusListType,
|
|
10
10
|
} from '@sphereon/ssi-types'
|
|
11
11
|
|
|
12
12
|
import { StatusList } from '@sphereon/vc-status-list'
|
|
13
|
-
import type { IStatusList } from './IStatusList'
|
|
13
|
+
import type { IStatusList, IStatusList2021ImplementationResult } from './IStatusList'
|
|
14
14
|
import type {
|
|
15
15
|
CheckStatusIndexArgs,
|
|
16
16
|
CreateStatusListArgs,
|
|
@@ -19,12 +19,12 @@ import type {
|
|
|
19
19
|
UpdateStatusListFromEncodedListArgs,
|
|
20
20
|
UpdateStatusListIndexArgs,
|
|
21
21
|
} from '../types'
|
|
22
|
-
|
|
23
|
-
import { Status2021 } from '../types'
|
|
22
|
+
import { Status2021, StatusList2021EntryCredentialStatus } from '../types'
|
|
24
23
|
import { assertValidProofType, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
|
|
24
|
+
import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusList2021Entity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
25
25
|
|
|
26
26
|
export const DEFAULT_LIST_LENGTH = 250000
|
|
27
|
-
export const DEFAULT_PROOF_FORMAT = 'lds' as
|
|
27
|
+
export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
|
|
28
28
|
|
|
29
29
|
export class StatusList2021Implementation implements IStatusList {
|
|
30
30
|
async createNewStatusList(
|
|
@@ -96,11 +96,15 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
96
96
|
context,
|
|
97
97
|
)
|
|
98
98
|
|
|
99
|
+
if (!('statusPurpose' in credentialSubject)) {
|
|
100
|
+
return Promise.reject(Error('statusPurpose is required in credentialSubject for StatusList2021'))
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
return {
|
|
100
104
|
statusListCredential: updatedCredential,
|
|
101
105
|
encodedList,
|
|
102
106
|
statusList2021: {
|
|
103
|
-
|
|
107
|
+
statusPurpose: credentialSubject.statusPurpose,
|
|
104
108
|
indexingDirection: 'rightToLeft',
|
|
105
109
|
},
|
|
106
110
|
length: statusList.length - 1,
|
|
@@ -126,7 +130,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
126
130
|
const { issuer, id } = getAssertedValues(args)
|
|
127
131
|
const statusList = await StatusList.decode({ encodedList: args.encodedList })
|
|
128
132
|
const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
|
|
129
|
-
statusList.setStatus(index, args.value)
|
|
133
|
+
statusList.setStatus(index, args.value !== 0)
|
|
130
134
|
|
|
131
135
|
const newEncodedList = await statusList.encode()
|
|
132
136
|
const credential = await this.createVerifiableCredential(
|
|
@@ -166,7 +170,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
166
170
|
return status ? Status2021.Invalid : Status2021.Valid
|
|
167
171
|
}
|
|
168
172
|
|
|
169
|
-
async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
|
|
173
|
+
async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IStatusList2021ImplementationResult> {
|
|
170
174
|
const { statusListPayload } = args
|
|
171
175
|
const uniform = CredentialMapper.toUniformCredential(statusListPayload)
|
|
172
176
|
const { issuer, credentialSubject } = uniform
|
|
@@ -175,9 +179,11 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
175
179
|
const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
|
|
176
180
|
|
|
177
181
|
const statusPurpose = getAssertedProperty('statusPurpose', credentialSubject)
|
|
182
|
+
const indexingDirection = 'rightToLeft'
|
|
178
183
|
const list = await StatusList.decode({ encodedList })
|
|
179
184
|
|
|
180
185
|
return {
|
|
186
|
+
// Base implementation fields
|
|
181
187
|
id,
|
|
182
188
|
encodedList,
|
|
183
189
|
issuer,
|
|
@@ -186,12 +192,41 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
186
192
|
length: list.length,
|
|
187
193
|
statusListCredential: statusListPayload,
|
|
188
194
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
195
|
+
correlationId: args.correlationId, // FIXME these do not need to be inside the impl
|
|
196
|
+
driverType: args.driverType, // FIXME these do not need to be inside the impl
|
|
197
|
+
|
|
198
|
+
// Flattened StatusList2021-specific fields
|
|
199
|
+
indexingDirection,
|
|
200
|
+
statusPurpose,
|
|
201
|
+
|
|
202
|
+
// Legacy nested structure for backward compatibility
|
|
189
203
|
statusList2021: {
|
|
190
|
-
indexingDirection
|
|
204
|
+
indexingDirection,
|
|
191
205
|
statusPurpose,
|
|
206
|
+
|
|
207
|
+
// Optional fields from args
|
|
208
|
+
...(args.correlationId && { correlationId: args.correlationId }),
|
|
209
|
+
...(args.driverType && { driverType: args.driverType }),
|
|
192
210
|
},
|
|
193
|
-
|
|
194
|
-
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async createCredentialStatus(args: {
|
|
215
|
+
statusList: StatusListEntity
|
|
216
|
+
statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
|
|
217
|
+
statusListIndex: number
|
|
218
|
+
}): Promise<StatusList2021EntryCredentialStatus> {
|
|
219
|
+
const { statusList, statusListIndex } = args
|
|
220
|
+
|
|
221
|
+
// Cast to StatusList2021Entity to access specific properties
|
|
222
|
+
const statusList2021 = statusList as StatusList2021Entity
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
226
|
+
type: 'StatusList2021Entry',
|
|
227
|
+
statusPurpose: statusList2021.statusPurpose ?? 'revocation',
|
|
228
|
+
statusListIndex: '' + statusListIndex,
|
|
229
|
+
statusListCredential: statusList.id,
|
|
195
230
|
}
|
|
196
231
|
}
|
|
197
232
|
|
|
@@ -234,7 +269,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
234
269
|
return CredentialMapper.toWrappedVerifiableCredential(verifiableCredential as StatusListCredential).original as StatusListCredential
|
|
235
270
|
}
|
|
236
271
|
|
|
237
|
-
private buildContentType(proofFormat:
|
|
272
|
+
private buildContentType(proofFormat: CredentialProofFormat | undefined) {
|
|
238
273
|
switch (proofFormat) {
|
|
239
274
|
case 'jwt':
|
|
240
275
|
return `application/statuslist+jwt`
|
|
@@ -2,6 +2,7 @@ import type { IStatusList } from './IStatusList'
|
|
|
2
2
|
import { StatusList2021Implementation } from './StatusList2021'
|
|
3
3
|
import { OAuthStatusListImplementation } from './OAuthStatusList'
|
|
4
4
|
import { StatusListType } from '@sphereon/ssi-types'
|
|
5
|
+
import { BitstringStatusListImplementation } from './BitstringStatusListImplementation'
|
|
5
6
|
|
|
6
7
|
export class StatusListFactory {
|
|
7
8
|
private static instance: StatusListFactory
|
|
@@ -11,6 +12,7 @@ export class StatusListFactory {
|
|
|
11
12
|
this.implementations = new Map()
|
|
12
13
|
this.implementations.set(StatusListType.StatusList2021, new StatusList2021Implementation())
|
|
13
14
|
this.implementations.set(StatusListType.OAuthStatusList, new OAuthStatusListImplementation())
|
|
15
|
+
this.implementations.set(StatusListType.BitstringStatusList, new BitstringStatusListImplementation())
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
public static getInstance(): StatusListFactory {
|
package/src/types/index.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
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
|
-
StatusListCredentialIdMode,
|
|
11
10
|
StatusListDriverType,
|
|
12
11
|
type StatusListIndexingDirection,
|
|
13
12
|
StatusListType,
|
|
@@ -26,6 +25,7 @@ import { DataSource } from 'typeorm'
|
|
|
26
25
|
import type { BitsPerStatus } from '@sd-jwt/jwt-status-list'
|
|
27
26
|
import type { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'
|
|
28
27
|
import type { StatusListOpts } from '@sphereon/oid4vci-common'
|
|
28
|
+
import { BitstringStatusPurpose } from '@4sure-tech/vc-bitstring-status-lists'
|
|
29
29
|
|
|
30
30
|
export enum StatusOAuth {
|
|
31
31
|
Valid = 0,
|
|
@@ -38,6 +38,8 @@ export enum Status2021 {
|
|
|
38
38
|
Invalid = 1,
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export type BitstringStatus = number
|
|
42
|
+
|
|
41
43
|
export type StatusList2021Args = {
|
|
42
44
|
indexingDirection: StatusListIndexingDirection
|
|
43
45
|
statusPurpose?: StatusPurpose2021
|
|
@@ -45,10 +47,18 @@ export type StatusList2021Args = {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export type OAuthStatusListArgs = {
|
|
48
|
-
bitsPerStatus
|
|
50
|
+
bitsPerStatus: BitsPerStatus
|
|
49
51
|
expiresAt?: Date
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
export type BitstringStatusListArgs = {
|
|
55
|
+
statusPurpose: BitstringStatusPurpose
|
|
56
|
+
bitsPerStatus: number
|
|
57
|
+
ttl?: number
|
|
58
|
+
validFrom?: Date
|
|
59
|
+
validUntil?: Date
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
export type BaseCreateNewStatusListArgs = {
|
|
53
63
|
type: StatusListType
|
|
54
64
|
id: string
|
|
@@ -59,6 +69,7 @@ export type BaseCreateNewStatusListArgs = {
|
|
|
59
69
|
keyRef?: string
|
|
60
70
|
statusList2021?: StatusList2021Args
|
|
61
71
|
oauthStatusList?: OAuthStatusListArgs
|
|
72
|
+
bitstringStatusList?: BitstringStatusListArgs
|
|
62
73
|
driverType?: StatusListDriverType
|
|
63
74
|
}
|
|
64
75
|
|
|
@@ -71,10 +82,18 @@ export type UpdateOAuthStatusListArgs = {
|
|
|
71
82
|
expiresAt?: Date
|
|
72
83
|
}
|
|
73
84
|
|
|
85
|
+
export type UpdateBitstringStatusListArgs = {
|
|
86
|
+
statusPurpose: BitstringStatusPurpose
|
|
87
|
+
bitsPerStatus: number
|
|
88
|
+
validFrom?: Date
|
|
89
|
+
validUntil?: Date
|
|
90
|
+
ttl?: number
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
export interface UpdateStatusListFromEncodedListArgs {
|
|
75
94
|
type?: StatusListType
|
|
76
95
|
statusListIndex: number | string
|
|
77
|
-
value:
|
|
96
|
+
value: number
|
|
78
97
|
proofFormat?: CredentialProofFormat
|
|
79
98
|
keyRef?: string
|
|
80
99
|
correlationId?: string
|
|
@@ -83,41 +102,57 @@ export interface UpdateStatusListFromEncodedListArgs {
|
|
|
83
102
|
id: string
|
|
84
103
|
statusList2021?: UpdateStatusList2021Args
|
|
85
104
|
oauthStatusList?: UpdateOAuthStatusListArgs
|
|
105
|
+
bitstringStatusList?: UpdateBitstringStatusListArgs
|
|
86
106
|
}
|
|
87
107
|
|
|
88
108
|
export interface UpdateStatusListFromStatusListCredentialArgs {
|
|
89
109
|
statusListCredential: StatusListCredential // | CompactJWT
|
|
90
110
|
keyRef?: string
|
|
91
111
|
statusListIndex: number | string
|
|
92
|
-
value: number | Status2021 | StatusOAuth
|
|
112
|
+
value: number | Status2021 | StatusOAuth | BitstringStatus
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
export interface StatusListResult {
|
|
116
|
+
id: string
|
|
96
117
|
encodedList: string
|
|
97
|
-
|
|
98
|
-
length: number
|
|
118
|
+
issuer: string | IIssuer
|
|
99
119
|
type: StatusListType
|
|
100
120
|
proofFormat: CredentialProofFormat
|
|
101
|
-
|
|
121
|
+
length: number
|
|
122
|
+
statusListCredential: StatusListCredential
|
|
102
123
|
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
124
|
correlationId?: string
|
|
109
125
|
driverType?: StatusListDriverType
|
|
110
|
-
credentialIdMode?: StatusListCredentialIdMode
|
|
111
|
-
}
|
|
112
126
|
|
|
113
|
-
|
|
114
|
-
indexingDirection
|
|
115
|
-
statusPurpose?: StatusPurpose2021
|
|
116
|
-
}
|
|
127
|
+
// Flattened StatusList2021 fields
|
|
128
|
+
indexingDirection?: StatusListIndexingDirection
|
|
129
|
+
statusPurpose?: StatusPurpose2021 | BitstringStatusPurpose | BitstringStatusPurpose[]
|
|
117
130
|
|
|
118
|
-
|
|
119
|
-
bitsPerStatus?:
|
|
131
|
+
// Flattened OAuth fields
|
|
132
|
+
bitsPerStatus?: number
|
|
120
133
|
expiresAt?: Date
|
|
134
|
+
|
|
135
|
+
// Flattened Bitstring fields
|
|
136
|
+
validFrom?: Date
|
|
137
|
+
validUntil?: Date
|
|
138
|
+
ttl?: number
|
|
139
|
+
|
|
140
|
+
// Legacy nested structures for backward compatibility
|
|
141
|
+
statusList2021?: {
|
|
142
|
+
indexingDirection: StatusListIndexingDirection
|
|
143
|
+
statusPurpose: StatusPurpose2021
|
|
144
|
+
}
|
|
145
|
+
oauthStatusList?: {
|
|
146
|
+
bitsPerStatus: number
|
|
147
|
+
expiresAt?: Date
|
|
148
|
+
}
|
|
149
|
+
bitstringStatusList?: {
|
|
150
|
+
statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
|
|
151
|
+
bitsPerStatus?: number
|
|
152
|
+
validFrom?: Date
|
|
153
|
+
validUntil?: Date
|
|
154
|
+
ttl?: number
|
|
155
|
+
}
|
|
121
156
|
}
|
|
122
157
|
|
|
123
158
|
export interface StatusList2021EntryCredentialStatus extends ICredentialStatus {
|
|
@@ -135,6 +170,16 @@ export interface StatusListOAuthEntryCredentialStatus extends ICredentialStatus
|
|
|
135
170
|
expiresAt?: Date
|
|
136
171
|
}
|
|
137
172
|
|
|
173
|
+
export interface BitstringStatusListEntryCredentialStatus extends ICredentialStatus {
|
|
174
|
+
type: 'BitstringStatusListEntry'
|
|
175
|
+
statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
|
|
176
|
+
statusListIndex: string
|
|
177
|
+
statusListCredential: string
|
|
178
|
+
bitsPerStatus?: number
|
|
179
|
+
statusMessage?: Array<BitstringStatus>
|
|
180
|
+
statusReference?: string | string[]
|
|
181
|
+
}
|
|
182
|
+
|
|
138
183
|
export interface StatusList2021ToVerifiableCredentialArgs {
|
|
139
184
|
issuer: string | IIssuer
|
|
140
185
|
id: string
|
|
@@ -154,12 +199,14 @@ export interface CreateStatusListArgs {
|
|
|
154
199
|
length?: number
|
|
155
200
|
statusList2021?: StatusList2021Args
|
|
156
201
|
oauthStatusList?: OAuthStatusListArgs
|
|
202
|
+
bitstringStatusList?: BitstringStatusListArgs
|
|
157
203
|
}
|
|
158
204
|
|
|
159
205
|
export interface UpdateStatusListIndexArgs {
|
|
160
206
|
statusListCredential: StatusListCredential // | CompactJWT
|
|
161
207
|
statusListIndex: number | string
|
|
162
|
-
value: number | Status2021 | StatusOAuth
|
|
208
|
+
value: number | Status2021 | StatusOAuth | BitstringStatus
|
|
209
|
+
bitsPerStatus?: number
|
|
163
210
|
keyRef?: string
|
|
164
211
|
expiresAt?: Date
|
|
165
212
|
}
|
|
@@ -167,12 +214,14 @@ export interface UpdateStatusListIndexArgs {
|
|
|
167
214
|
export interface CheckStatusIndexArgs {
|
|
168
215
|
statusListCredential: StatusListCredential // | CompactJWT
|
|
169
216
|
statusListIndex: string | number
|
|
217
|
+
bitsPerStatus?: number
|
|
170
218
|
}
|
|
171
219
|
|
|
172
220
|
export interface ToStatusListDetailsArgs {
|
|
173
221
|
statusListPayload: StatusListCredential
|
|
174
222
|
correlationId?: string
|
|
175
223
|
driverType?: StatusListDriverType
|
|
224
|
+
bitsPerStatus?: number
|
|
176
225
|
}
|
|
177
226
|
|
|
178
227
|
/**
|
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'
|
|
42
|
+
[StatusListType.StatusList2021, ['jwt', 'lds']],
|
|
43
43
|
[StatusListType.OAuthStatusList, ['jwt', 'cbor']],
|
|
44
|
+
[StatusListType.BitstringStatusList, ['lds']],
|
|
44
45
|
])
|
|
45
46
|
|
|
46
47
|
export function assertValidProofType(type: StatusListType, proofFormat: CredentialProofFormat) {
|
|
@@ -93,3 +94,35 @@ export function determineProofFormat(credential: StatusListCredential): Credenti
|
|
|
93
94
|
throw Error('Cannot determine credential payload type')
|
|
94
95
|
}
|
|
95
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Ensures a value is converted to a Date object if it's a valid date string,
|
|
100
|
+
* otherwise returns the original value or undefined
|
|
101
|
+
*
|
|
102
|
+
* @param value - The value to convert to Date (can be Date, string, or undefined)
|
|
103
|
+
* @returns Date object, undefined, or the original value if conversion fails
|
|
104
|
+
*/
|
|
105
|
+
export function ensureDate(value: Date | string | undefined): Date | undefined {
|
|
106
|
+
if (value === undefined || value === null) {
|
|
107
|
+
return undefined
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (value instanceof Date) {
|
|
111
|
+
return value
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (typeof value === 'string') {
|
|
115
|
+
if (value.trim() === '') {
|
|
116
|
+
return undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const date = new Date(value)
|
|
120
|
+
// Check if the date is valid
|
|
121
|
+
if (isNaN(date.getTime())) {
|
|
122
|
+
return undefined
|
|
123
|
+
}
|
|
124
|
+
return date
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return undefined
|
|
128
|
+
}
|