@sphereon/ssi-sdk.vc-status-list 0.34.1-feature.SSISDK.17.bitstring.sl.11 → 0.34.1-feature.SSISDK.17.bitstring.sl.13
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 +114 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -8
- package/dist/index.d.ts +10 -8
- package/dist/index.js +115 -65
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/functions.ts +8 -29
- package/src/impl/BitstringStatusListImplementation.ts +159 -62
- package/src/impl/IStatusList.ts +8 -4
- package/src/impl/OAuthStatusList.ts +4 -3
- package/src/impl/StatusList2021.ts +6 -5
- package/src/types/index.ts +4 -11
- package/src/utils.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.vc-status-list",
|
|
3
3
|
"description": "Sphereon SSI-SDK plugin for Status List management, like StatusList2021.",
|
|
4
|
-
"version": "0.34.1-feature.SSISDK.17.bitstring.sl.
|
|
4
|
+
"version": "0.34.1-feature.SSISDK.17.bitstring.sl.13+61bcf6d3",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.cjs",
|
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
"@sphereon/ssi-sdk-ext.did-utils": "0.29.0",
|
|
32
32
|
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.29.0",
|
|
33
33
|
"@sphereon/ssi-sdk-ext.jwt-service": "0.29.0",
|
|
34
|
-
"@sphereon/ssi-sdk.
|
|
35
|
-
"@sphereon/ssi-
|
|
34
|
+
"@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.SSISDK.17.bitstring.sl.13+61bcf6d3",
|
|
35
|
+
"@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.17.bitstring.sl.13+61bcf6d3",
|
|
36
|
+
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.17.bitstring.sl.13+61bcf6d3",
|
|
36
37
|
"@sphereon/vc-status-list": "7.0.0-next.0",
|
|
37
38
|
"@veramo/core": "4.2.0",
|
|
38
39
|
"@veramo/credential-status": "4.2.0",
|
|
@@ -71,5 +72,5 @@
|
|
|
71
72
|
"SSI",
|
|
72
73
|
"StatusList2021"
|
|
73
74
|
],
|
|
74
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "61bcf6d37bcb3d77036b5415d72853c3ba3f9273"
|
|
75
76
|
}
|
package/src/functions.ts
CHANGED
|
@@ -2,13 +2,12 @@ import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-res
|
|
|
2
2
|
import {
|
|
3
3
|
CredentialMapper,
|
|
4
4
|
type CredentialProofFormat,
|
|
5
|
-
DocumentFormat,
|
|
6
5
|
type StatusListCredential,
|
|
7
6
|
StatusListDriverType,
|
|
8
7
|
StatusListType,
|
|
9
8
|
type StatusPurpose2021,
|
|
10
9
|
} from '@sphereon/ssi-types'
|
|
11
|
-
import type { CredentialStatus, DIDDocument, IAgentContext,
|
|
10
|
+
import type { CredentialStatus, DIDDocument, IAgentContext, ProofFormat as VeramoProofFormat } from '@veramo/core'
|
|
12
11
|
|
|
13
12
|
import { IAddStatusListArgs, IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
14
13
|
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
} from './types'
|
|
32
31
|
import { assertValidProofType, determineStatusListType, getAssertedValue, getAssertedValues } from './utils'
|
|
33
32
|
import { getStatusListImplementation } from './impl/StatusListFactory'
|
|
33
|
+
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
34
34
|
|
|
35
35
|
export async function fetchStatusListCredential(args: { statusListCredential: string }): Promise<StatusListCredential> {
|
|
36
36
|
const url = getAssertedValue('statusListCredential', args.statusListCredential)
|
|
@@ -164,7 +164,7 @@ export async function checkStatusIndexFromStatusListCredential(args: {
|
|
|
164
164
|
|
|
165
165
|
export async function createNewStatusList(
|
|
166
166
|
args: CreateNewStatusListFuncArgs,
|
|
167
|
-
context: IAgentContext<(
|
|
167
|
+
context: IAgentContext<(IVcdmCredentialPlugin | any) /*IvcdMCredentialPlugin is not available*/ & IIdentifierResolution>,
|
|
168
168
|
): Promise<StatusListResult> {
|
|
169
169
|
const { type } = getAssertedValues(args)
|
|
170
170
|
const implementation = getStatusListImplementation(type)
|
|
@@ -173,7 +173,7 @@ export async function createNewStatusList(
|
|
|
173
173
|
|
|
174
174
|
export async function updateStatusIndexFromStatusListCredential(
|
|
175
175
|
args: UpdateStatusListIndexArgs,
|
|
176
|
-
context: IAgentContext<
|
|
176
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
177
177
|
): Promise<StatusListResult> {
|
|
178
178
|
const credential = getAssertedValue('statusListCredential', args.statusListCredential)
|
|
179
179
|
const statusListType: StatusListType = determineStatusListType(credential)
|
|
@@ -182,40 +182,19 @@ export async function updateStatusIndexFromStatusListCredential(
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
export async function statusListCredentialToDetails({
|
|
185
|
+
statusListType,
|
|
185
186
|
correlationId,
|
|
186
187
|
driverType,
|
|
187
188
|
statusListCredential,
|
|
188
189
|
bitsPerStatus,
|
|
189
190
|
}: {
|
|
191
|
+
statusListType: StatusListType
|
|
190
192
|
statusListCredential: StatusListCredential
|
|
191
193
|
correlationId?: string
|
|
192
194
|
driverType?: StatusListDriverType
|
|
193
195
|
bitsPerStatus?: number
|
|
194
196
|
}): Promise<StatusListResult & Partial<IAddStatusListArgs>> {
|
|
195
197
|
const credential = getAssertedValue('statusListCredential', statusListCredential)
|
|
196
|
-
|
|
197
|
-
let statusListType: StatusListType | undefined
|
|
198
|
-
const documentFormat = CredentialMapper.detectDocumentType(credential)
|
|
199
|
-
if (documentFormat === DocumentFormat.JWT) {
|
|
200
|
-
const [header] = credential.split('.')
|
|
201
|
-
const decodedHeader = JSON.parse(Buffer.from(header, 'base64').toString())
|
|
202
|
-
|
|
203
|
-
if (decodedHeader.typ === 'statuslist+jwt') {
|
|
204
|
-
statusListType = StatusListType.OAuthStatusList
|
|
205
|
-
}
|
|
206
|
-
} else if (documentFormat === DocumentFormat.MSO_MDOC) {
|
|
207
|
-
statusListType = StatusListType.OAuthStatusList
|
|
208
|
-
// TODO check CBOR content?
|
|
209
|
-
}
|
|
210
|
-
if (!statusListType) {
|
|
211
|
-
const uniform = CredentialMapper.toUniformCredential(credential)
|
|
212
|
-
const type = uniform.type.find((t) => t.includes('StatusList2021') || t.includes('OAuth2StatusList') || t.includes('BitstringStatusList'))
|
|
213
|
-
if (!type) {
|
|
214
|
-
throw new Error('Invalid status list credential type')
|
|
215
|
-
}
|
|
216
|
-
statusListType = type.replace('Credential', '') as StatusListType
|
|
217
|
-
}
|
|
218
|
-
|
|
219
198
|
const implementation = getStatusListImplementation(statusListType)
|
|
220
199
|
|
|
221
200
|
// The implementation should now return all the type-specific fields needed for the entity
|
|
@@ -250,7 +229,7 @@ export async function createCredentialStatusFromStatusList(args: {
|
|
|
250
229
|
|
|
251
230
|
export async function updateStatusListIndexFromEncodedList(
|
|
252
231
|
args: UpdateStatusListFromEncodedListArgs,
|
|
253
|
-
context: IAgentContext<
|
|
232
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
254
233
|
): Promise<StatusListResult> {
|
|
255
234
|
const { type } = getAssertedValue('type', args)
|
|
256
235
|
const implementation = getStatusListImplementation(type!)
|
|
@@ -259,7 +238,7 @@ export async function updateStatusListIndexFromEncodedList(
|
|
|
259
238
|
|
|
260
239
|
export async function statusList2021ToVerifiableCredential(
|
|
261
240
|
args: StatusList2021ToVerifiableCredentialArgs,
|
|
262
|
-
context: IAgentContext<
|
|
241
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
263
242
|
): Promise<StatusListCredential> {
|
|
264
243
|
const { issuer, id, type } = getAssertedValues(args)
|
|
265
244
|
const identifier = await context.agent.identifierManagedGet({
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Bitstring Status List Implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the W3C Bitstring Status List specification for managing
|
|
5
|
+
* credential status information. It provides functionality to create, update, and
|
|
6
|
+
* check the status of verifiable credentials using compressed bitstring status lists.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Create new bitstring status lists with configurable purposes and bit sizes
|
|
10
|
+
* - Update individual credential status entries in existing lists
|
|
11
|
+
* - Check the status of specific credentials by index
|
|
12
|
+
* - Support for multiple proof formats (JWT, LDS, CBOR)
|
|
13
|
+
* - Integration with Veramo agent context for credential signing
|
|
14
|
+
*
|
|
15
|
+
* @author Sphereon International B.V.
|
|
16
|
+
* @since 2024
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { IAgentContext } from '@veramo/core'
|
|
2
20
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
3
21
|
|
|
4
22
|
import {
|
|
@@ -24,17 +42,37 @@ import {
|
|
|
24
42
|
|
|
25
43
|
import { assertValidProofType, ensureDate, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
|
|
26
44
|
import { BitstringStatusListCredential } from '../types/BitstringStatusList'
|
|
27
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
BitstreamStatusList,
|
|
47
|
+
BitstringStatusListCredentialUnsigned,
|
|
48
|
+
BitstringStatusPurpose,
|
|
49
|
+
createStatusListCredential,
|
|
50
|
+
} from '@4sure-tech/vc-bitstring-status-lists'
|
|
28
51
|
import { BitstringStatusListEntity, IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
52
|
+
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
29
53
|
|
|
30
54
|
export const DEFAULT_LIST_LENGTH = 131072 // W3C spec minimum
|
|
31
55
|
export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
|
|
32
56
|
export const DEFAULT_STATUS_PURPOSE: BitstringStatusPurpose = 'revocation'
|
|
33
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Implementation of the IStatusList interface for W3C Bitstring Status Lists
|
|
60
|
+
*
|
|
61
|
+
* This class handles the creation, updating, and verification of bitstring status lists
|
|
62
|
+
* according to the W3C Bitstring Status List specification. It supports multiple
|
|
63
|
+
* status purposes (revocation, suspension, etc.) and various proof formats.
|
|
64
|
+
*/
|
|
34
65
|
export class BitstringStatusListImplementation implements IStatusList {
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new bitstring status list with the specified configuration
|
|
68
|
+
*
|
|
69
|
+
* @param args - Configuration for the new status list including issuer, purpose, and size
|
|
70
|
+
* @param context - Veramo agent context for credential operations
|
|
71
|
+
* @returns Promise resolving to the created status list details
|
|
72
|
+
*/
|
|
35
73
|
async createNewStatusList(
|
|
36
74
|
args: CreateStatusListArgs,
|
|
37
|
-
context: IAgentContext<
|
|
75
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
38
76
|
): Promise<StatusListResult> {
|
|
39
77
|
if (!args.bitstringStatusList) {
|
|
40
78
|
throw new Error('BitstringStatusList options are required for type BitstringStatusList')
|
|
@@ -43,30 +81,37 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
43
81
|
const length = args?.length ?? DEFAULT_LIST_LENGTH
|
|
44
82
|
const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
|
|
45
83
|
assertValidProofType(StatusListType.BitstringStatusList, proofFormat)
|
|
46
|
-
const veramoProofFormat: VeramoProofFormat = proofFormat as VeramoProofFormat
|
|
47
84
|
|
|
48
85
|
const { issuer, id } = args
|
|
49
86
|
const correlationId = getAssertedValue('correlationId', args.correlationId)
|
|
50
87
|
const { statusPurpose, bitsPerStatus, validFrom, validUntil, ttl } = args.bitstringStatusList
|
|
88
|
+
|
|
89
|
+
const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
|
|
90
|
+
id,
|
|
91
|
+
issuer,
|
|
92
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
93
|
+
validFrom: ensureDate(validFrom),
|
|
94
|
+
validUntil: ensureDate(validUntil),
|
|
95
|
+
ttl,
|
|
96
|
+
})
|
|
51
97
|
const statusListCredential = await this.createVerifiableCredential(
|
|
52
98
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
ttl,
|
|
99
|
+
unsignedCredential,
|
|
100
|
+
id,
|
|
101
|
+
issuer,
|
|
102
|
+
proofFormat,
|
|
103
|
+
keyRef: args.keyRef,
|
|
59
104
|
},
|
|
60
105
|
context,
|
|
61
106
|
)
|
|
62
107
|
|
|
63
108
|
return {
|
|
64
|
-
encodedList:
|
|
65
|
-
statusListCredential
|
|
109
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
110
|
+
statusListCredential,
|
|
66
111
|
bitstringStatusList: {
|
|
67
112
|
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
68
|
-
...(
|
|
69
|
-
...(
|
|
113
|
+
...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
|
|
114
|
+
...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
|
|
70
115
|
ttl,
|
|
71
116
|
bitsPerStatus,
|
|
72
117
|
},
|
|
@@ -80,12 +125,19 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
80
125
|
}
|
|
81
126
|
}
|
|
82
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Updates the status of a specific credential in an existing status list
|
|
130
|
+
*
|
|
131
|
+
* @param args - Update parameters including the status list credential, index, and new value
|
|
132
|
+
* @param context - Veramo agent context for credential operations
|
|
133
|
+
* @returns Promise resolving to the updated status list details
|
|
134
|
+
*/
|
|
83
135
|
async updateStatusListIndex(
|
|
84
136
|
args: UpdateStatusListIndexArgs,
|
|
85
|
-
context: IAgentContext<
|
|
137
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
86
138
|
): Promise<StatusListResult> {
|
|
87
139
|
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
88
|
-
return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)')
|
|
140
|
+
return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)'))
|
|
89
141
|
}
|
|
90
142
|
|
|
91
143
|
const credential = args.statusListCredential
|
|
@@ -108,74 +160,92 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
108
160
|
const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : undefined
|
|
109
161
|
const ttl = credSubject.ttl
|
|
110
162
|
|
|
163
|
+
const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
|
|
164
|
+
id,
|
|
165
|
+
issuer,
|
|
166
|
+
statusList,
|
|
167
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
168
|
+
validFrom: ensureDate(validFrom),
|
|
169
|
+
validUntil: ensureDate(validUntil),
|
|
170
|
+
ttl,
|
|
171
|
+
})
|
|
172
|
+
|
|
111
173
|
const updatedCredential = await this.createVerifiableCredential(
|
|
112
174
|
{
|
|
113
|
-
|
|
175
|
+
unsignedCredential,
|
|
114
176
|
id,
|
|
115
177
|
issuer,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
statusPurpose,
|
|
119
|
-
ttl,
|
|
120
|
-
validFrom,
|
|
121
|
-
validUntil,
|
|
178
|
+
proofFormat,
|
|
179
|
+
keyRef: args.keyRef,
|
|
122
180
|
},
|
|
123
181
|
context,
|
|
124
182
|
)
|
|
125
183
|
|
|
126
184
|
return {
|
|
127
185
|
statusListCredential: updatedCredential,
|
|
128
|
-
encodedList:
|
|
186
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
129
187
|
bitstringStatusList: {
|
|
130
188
|
statusPurpose,
|
|
131
|
-
...(
|
|
132
|
-
...(
|
|
189
|
+
...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
|
|
190
|
+
...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
|
|
133
191
|
bitsPerStatus: args.bitsPerStatus,
|
|
134
192
|
ttl,
|
|
135
193
|
},
|
|
136
194
|
length: statusList.getLength(),
|
|
137
195
|
type: StatusListType.BitstringStatusList,
|
|
138
|
-
proofFormat
|
|
196
|
+
proofFormat,
|
|
139
197
|
id,
|
|
140
198
|
issuer,
|
|
141
199
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
142
200
|
}
|
|
143
201
|
}
|
|
144
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Updates a status list by decoding an encoded list, modifying it, and re-encoding
|
|
205
|
+
*
|
|
206
|
+
* @param args - Update parameters including encoded list, index, and new value
|
|
207
|
+
* @param context - Veramo agent context for credential operations
|
|
208
|
+
* @returns Promise resolving to the updated status list details
|
|
209
|
+
*/
|
|
145
210
|
async updateStatusListFromEncodedList(
|
|
146
211
|
args: UpdateStatusListFromEncodedListArgs,
|
|
147
|
-
context: IAgentContext<
|
|
212
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
148
213
|
): Promise<StatusListResult> {
|
|
149
214
|
if (!args.bitstringStatusList) {
|
|
150
215
|
throw new Error('bitstringStatusList options required for type BitstringStatusList')
|
|
151
216
|
}
|
|
152
217
|
|
|
153
218
|
if (args.bitstringStatusList.bitsPerStatus < 1) {
|
|
154
|
-
return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)')
|
|
219
|
+
return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)'))
|
|
155
220
|
}
|
|
156
221
|
|
|
157
222
|
const { statusPurpose, bitsPerStatus, ttl, validFrom, validUntil } = args.bitstringStatusList
|
|
158
223
|
|
|
159
224
|
const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
|
|
160
225
|
assertValidProofType(StatusListType.BitstringStatusList, proofFormat)
|
|
161
|
-
const veramoProofFormat: VeramoProofFormat = proofFormat as VeramoProofFormat
|
|
162
226
|
|
|
163
227
|
const { issuer, id } = getAssertedValues(args)
|
|
164
228
|
const statusList: BitstreamStatusList = await BitstreamStatusList.decode({ encodedList: args.encodedList, statusSize: bitsPerStatus })
|
|
165
229
|
const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
|
|
166
230
|
statusList.setStatus(index, args.value)
|
|
167
231
|
|
|
232
|
+
const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
|
|
233
|
+
id,
|
|
234
|
+
issuer,
|
|
235
|
+
statusList,
|
|
236
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
237
|
+
validFrom: ensureDate(validFrom),
|
|
238
|
+
validUntil: ensureDate(validUntil),
|
|
239
|
+
ttl,
|
|
240
|
+
})
|
|
241
|
+
|
|
168
242
|
const credential = await this.createVerifiableCredential(
|
|
169
243
|
{
|
|
244
|
+
unsignedCredential,
|
|
170
245
|
id,
|
|
171
246
|
issuer,
|
|
172
|
-
|
|
173
|
-
proofFormat: veramoProofFormat,
|
|
247
|
+
proofFormat,
|
|
174
248
|
keyRef: args.keyRef,
|
|
175
|
-
statusPurpose,
|
|
176
|
-
validFrom: ensureDate(validFrom),
|
|
177
|
-
validUntil: ensureDate(validUntil),
|
|
178
|
-
ttl,
|
|
179
249
|
},
|
|
180
250
|
context,
|
|
181
251
|
)
|
|
@@ -183,34 +253,38 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
183
253
|
return {
|
|
184
254
|
type: StatusListType.BitstringStatusList,
|
|
185
255
|
statusListCredential: credential,
|
|
186
|
-
encodedList:
|
|
256
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
187
257
|
bitstringStatusList: {
|
|
188
258
|
statusPurpose,
|
|
189
259
|
bitsPerStatus,
|
|
190
|
-
...(
|
|
191
|
-
...(
|
|
260
|
+
...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
|
|
261
|
+
...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
|
|
192
262
|
ttl,
|
|
193
263
|
},
|
|
194
264
|
length: statusList.getLength(),
|
|
195
265
|
proofFormat: args.proofFormat ?? 'lds',
|
|
196
|
-
id
|
|
197
|
-
issuer
|
|
266
|
+
id,
|
|
267
|
+
issuer,
|
|
198
268
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
199
269
|
}
|
|
200
270
|
}
|
|
201
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Checks the status of a specific credential by its index in the status list
|
|
274
|
+
*
|
|
275
|
+
* @param args - Check parameters including the status list credential and index
|
|
276
|
+
* @returns Promise resolving to the status value at the specified index
|
|
277
|
+
*/
|
|
202
278
|
async checkStatusIndex(args: CheckStatusIndexArgs): Promise<BitstringStatus> {
|
|
203
279
|
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
204
|
-
return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)')
|
|
280
|
+
return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)'))
|
|
205
281
|
}
|
|
206
282
|
|
|
207
283
|
const uniform = CredentialMapper.toUniformCredential(args.statusListCredential)
|
|
208
284
|
const { credentialSubject } = uniform
|
|
209
285
|
const encodedList = getAssertedProperty('encodedList', credentialSubject)
|
|
210
286
|
|
|
211
|
-
const
|
|
212
|
-
const statusList = await BitstreamStatusList.decode({ encodedList, statusSize })
|
|
213
|
-
|
|
287
|
+
const statusList = await BitstreamStatusList.decode({ encodedList, statusSize: args.bitsPerStatus })
|
|
214
288
|
const numIndex = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
|
|
215
289
|
if (statusList.getLength() <= numIndex) {
|
|
216
290
|
throw new Error(`Status list index out of bounds, has ${statusList.getLength()} entries, requested ${numIndex}`)
|
|
@@ -218,17 +292,23 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
218
292
|
return statusList.getStatus(numIndex)
|
|
219
293
|
}
|
|
220
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Converts a status list credential payload to detailed status list information
|
|
297
|
+
*
|
|
298
|
+
* @param args - Conversion parameters including the status list payload
|
|
299
|
+
* @returns Promise resolving to detailed status list information
|
|
300
|
+
*/
|
|
221
301
|
async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IBitstringStatusListImplementationResult> {
|
|
222
302
|
const { statusListPayload, bitsPerStatus } = args
|
|
223
303
|
if (!bitsPerStatus || bitsPerStatus < 1) {
|
|
224
|
-
return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (toStatusListDetails)')
|
|
304
|
+
return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (toStatusListDetails)'))
|
|
225
305
|
}
|
|
226
306
|
|
|
227
307
|
const uniform = CredentialMapper.toUniformCredential(statusListPayload)
|
|
228
308
|
const { issuer, credentialSubject } = uniform
|
|
229
309
|
const id = getAssertedValue('id', uniform.id)
|
|
230
310
|
const encodedList = getAssertedProperty('encodedList', credentialSubject)
|
|
231
|
-
const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
|
|
311
|
+
const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'vc+jwt' : 'lds'
|
|
232
312
|
const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
|
|
233
313
|
const statusPurpose = getAssertedProperty('statusPurpose', credSubject)
|
|
234
314
|
const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : undefined
|
|
@@ -271,6 +351,12 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
271
351
|
}
|
|
272
352
|
}
|
|
273
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Creates a credential status entry for a specific credential in a status list
|
|
356
|
+
*
|
|
357
|
+
* @param args - Parameters including the status list, entry details, and index
|
|
358
|
+
* @returns Promise resolving to the credential status entry
|
|
359
|
+
*/
|
|
274
360
|
async createCredentialStatus(args: {
|
|
275
361
|
statusList: StatusListEntity
|
|
276
362
|
statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
|
|
@@ -300,44 +386,55 @@ export class BitstringStatusListImplementation implements IStatusList {
|
|
|
300
386
|
} satisfies BitstringStatusListEntryCredentialStatus
|
|
301
387
|
}
|
|
302
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Creates a signed verifiable credential from an unsigned status list credential
|
|
391
|
+
*
|
|
392
|
+
* @param args - Parameters including the unsigned credential and signing details
|
|
393
|
+
* @param context - Veramo agent context for credential operations
|
|
394
|
+
* @returns Promise resolving to the signed credential
|
|
395
|
+
*/
|
|
303
396
|
private async createVerifiableCredential(
|
|
304
397
|
args: {
|
|
398
|
+
unsignedCredential: BitstringStatusListCredentialUnsigned
|
|
305
399
|
id: string
|
|
306
400
|
issuer: string | IIssuer
|
|
307
|
-
|
|
308
|
-
proofFormat: VeramoProofFormat
|
|
309
|
-
statusPurpose: BitstringStatusPurpose
|
|
310
|
-
validFrom?: Date
|
|
311
|
-
validUntil?: Date
|
|
312
|
-
ttl?: number
|
|
401
|
+
proofFormat: CredentialProofFormat
|
|
313
402
|
keyRef?: string
|
|
314
403
|
},
|
|
315
|
-
context: IAgentContext<
|
|
404
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
316
405
|
): Promise<BitstringStatusListCredential> {
|
|
406
|
+
const { unsignedCredential, issuer, proofFormat, keyRef } = args
|
|
407
|
+
|
|
317
408
|
const identifier = await context.agent.identifierManagedGet({
|
|
318
|
-
identifier: typeof
|
|
409
|
+
identifier: typeof issuer === 'string' ? issuer : issuer.id,
|
|
319
410
|
vmRelationship: 'assertionMethod',
|
|
320
411
|
offlineWhenNoDIDRegistered: true,
|
|
321
412
|
})
|
|
322
413
|
|
|
323
|
-
const unsignedCredential = await createStatusListCredential(args)
|
|
324
|
-
|
|
325
414
|
const verifiableCredential = await context.agent.createVerifiableCredential({
|
|
326
415
|
credential: unsignedCredential,
|
|
327
|
-
keyRef:
|
|
328
|
-
proofFormat
|
|
416
|
+
keyRef: keyRef ?? identifier.kmsKeyRef,
|
|
417
|
+
proofFormat,
|
|
329
418
|
fetchRemoteContexts: true,
|
|
330
419
|
})
|
|
331
420
|
|
|
332
421
|
return CredentialMapper.toWrappedVerifiableCredential(verifiableCredential as StatusListCredential).original as BitstringStatusListCredential
|
|
333
422
|
}
|
|
334
423
|
|
|
335
|
-
|
|
424
|
+
/**
|
|
425
|
+
* Builds the appropriate content type string for a given proof format
|
|
426
|
+
*
|
|
427
|
+
* @param proofFormat - The proof format to build content type for
|
|
428
|
+
* @returns The corresponding content type string
|
|
429
|
+
*/
|
|
430
|
+
private buildContentType(proofFormat: CredentialProofFormat | undefined): string {
|
|
336
431
|
switch (proofFormat) {
|
|
337
432
|
case 'jwt':
|
|
338
|
-
return
|
|
433
|
+
return 'application/statuslist+jwt'
|
|
339
434
|
case 'cbor':
|
|
340
|
-
return
|
|
435
|
+
return 'application/statuslist+cwt'
|
|
436
|
+
case 'vc+jwt':
|
|
437
|
+
return 'application/statuslist+vc+jwt'
|
|
341
438
|
case 'lds':
|
|
342
439
|
return 'application/statuslist+ld+json'
|
|
343
440
|
default:
|
package/src/impl/IStatusList.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAgentContext
|
|
1
|
+
import type { IAgentContext } from '@veramo/core'
|
|
2
2
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
3
3
|
import {
|
|
4
4
|
BitstringStatus,
|
|
@@ -25,24 +25,28 @@ import {
|
|
|
25
25
|
StatusPurpose2021,
|
|
26
26
|
} from '@sphereon/ssi-types'
|
|
27
27
|
import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
28
|
+
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
28
29
|
|
|
29
30
|
export interface IStatusList {
|
|
30
31
|
/**
|
|
31
32
|
* Creates a new status list of the specific type
|
|
32
33
|
*/
|
|
33
|
-
createNewStatusList(args: CreateStatusListArgs, context: IAgentContext<
|
|
34
|
+
createNewStatusList(args: CreateStatusListArgs, context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>): Promise<StatusListResult>
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Updates a status at the given index in the status list
|
|
37
38
|
*/
|
|
38
|
-
updateStatusListIndex(
|
|
39
|
+
updateStatusListIndex(
|
|
40
|
+
args: UpdateStatusListIndexArgs,
|
|
41
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
42
|
+
): Promise<StatusListResult>
|
|
39
43
|
|
|
40
44
|
/**
|
|
41
45
|
* Updates a status list using a base64 encoded list of statuses
|
|
42
46
|
*/
|
|
43
47
|
updateStatusListFromEncodedList(
|
|
44
48
|
args: UpdateStatusListFromEncodedListArgs,
|
|
45
|
-
context: IAgentContext<
|
|
49
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
46
50
|
): Promise<StatusListResult>
|
|
47
51
|
|
|
48
52
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAgentContext,
|
|
1
|
+
import type { IAgentContext, IKeyManager } from '@veramo/core'
|
|
2
2
|
import { type CompactJWT, type CredentialProofFormat, type CWT, StatusListType } from '@sphereon/ssi-types'
|
|
3
3
|
import type {
|
|
4
4
|
CheckStatusIndexArgs,
|
|
@@ -19,8 +19,9 @@ import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-res
|
|
|
19
19
|
import { createSignedJwt, decodeStatusListJWT } from './encoding/jwt'
|
|
20
20
|
import { createSignedCbor, decodeStatusListCWT } from './encoding/cbor'
|
|
21
21
|
import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, OAuthStatusListEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
22
|
+
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
22
23
|
|
|
23
|
-
type IRequiredContext = IAgentContext<
|
|
24
|
+
type IRequiredContext = IAgentContext<IVcdmCredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>
|
|
24
25
|
|
|
25
26
|
export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
|
|
26
27
|
export const DEFAULT_LIST_LENGTH = 250000
|
|
@@ -227,7 +228,7 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
227
228
|
|
|
228
229
|
private async createSignedStatusList(
|
|
229
230
|
proofFormat: CredentialProofFormat,
|
|
230
|
-
context: IAgentContext<
|
|
231
|
+
context: IAgentContext<IVcdmCredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
|
|
231
232
|
statusList: StatusList,
|
|
232
233
|
issuerString: string,
|
|
233
234
|
id: string,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAgentContext,
|
|
1
|
+
import type { IAgentContext, ProofFormat as VeramoProofFormat } from '@veramo/core'
|
|
2
2
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
3
3
|
import {
|
|
4
4
|
CredentialMapper,
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
import { Status2021, StatusList2021EntryCredentialStatus } from '../types'
|
|
23
23
|
import { assertValidProofType, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
|
|
24
24
|
import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusList2021Entity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
25
|
+
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
25
26
|
|
|
26
27
|
export const DEFAULT_LIST_LENGTH = 250000
|
|
27
28
|
export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
|
|
@@ -29,7 +30,7 @@ export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
|
|
|
29
30
|
export class StatusList2021Implementation implements IStatusList {
|
|
30
31
|
async createNewStatusList(
|
|
31
32
|
args: CreateStatusListArgs,
|
|
32
|
-
context: IAgentContext<
|
|
33
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
33
34
|
): Promise<StatusListResult> {
|
|
34
35
|
const length = args?.length ?? DEFAULT_LIST_LENGTH
|
|
35
36
|
const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
|
|
@@ -71,7 +72,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
71
72
|
|
|
72
73
|
async updateStatusListIndex(
|
|
73
74
|
args: UpdateStatusListIndexArgs,
|
|
74
|
-
context: IAgentContext<
|
|
75
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
75
76
|
): Promise<StatusListResult> {
|
|
76
77
|
const credential = args.statusListCredential
|
|
77
78
|
const uniform = CredentialMapper.toUniformCredential(credential)
|
|
@@ -118,7 +119,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
118
119
|
|
|
119
120
|
async updateStatusListFromEncodedList(
|
|
120
121
|
args: UpdateStatusListFromEncodedListArgs,
|
|
121
|
-
context: IAgentContext<
|
|
122
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
122
123
|
): Promise<StatusListResult> {
|
|
123
124
|
if (!args.statusList2021) {
|
|
124
125
|
throw new Error('statusList2021 options required for type StatusList2021')
|
|
@@ -238,7 +239,7 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
238
239
|
proofFormat: VeramoProofFormat
|
|
239
240
|
keyRef?: string
|
|
240
241
|
},
|
|
241
|
-
context: IAgentContext<
|
|
242
|
+
context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
|
|
242
243
|
): Promise<StatusListCredential> {
|
|
243
244
|
const identifier = await context.agent.identifierManagedGet({
|
|
244
245
|
identifier: typeof args.issuer === 'string' ? args.issuer : args.issuer.id,
|