@sphereon/ssi-sdk.vc-status-list 0.34.1-feature.SSISDK.17.bitstring.sl.13 → 0.34.1-feature.SSISDK.17.bitstring.sl.16
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 +303 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -43
- package/dist/index.d.ts +117 -43
- package/dist/index.js +303 -159
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/functions.ts +100 -36
- package/src/impl/BitstringStatusListImplementation.ts +117 -65
- package/src/impl/IStatusList.ts +35 -7
- package/src/impl/OAuthStatusList.ts +82 -30
- package/src/impl/StatusList2021.ts +78 -34
- package/src/index.ts +1 -0
- package/src/types/index.ts +18 -39
- package/src/utils.ts +47 -18
|
@@ -3,16 +3,17 @@ import { type CompactJWT, type CredentialProofFormat, type CWT, StatusListType }
|
|
|
3
3
|
import type {
|
|
4
4
|
CheckStatusIndexArgs,
|
|
5
5
|
CreateStatusListArgs,
|
|
6
|
+
IMergeDetailsWithEntityArgs,
|
|
7
|
+
IToDetailsFromCredentialArgs,
|
|
6
8
|
SignedStatusListData,
|
|
7
9
|
StatusListOAuthEntryCredentialStatus,
|
|
8
10
|
StatusListResult,
|
|
9
11
|
StatusOAuth,
|
|
10
|
-
ToStatusListDetailsArgs,
|
|
11
12
|
UpdateStatusListFromEncodedListArgs,
|
|
12
13
|
UpdateStatusListIndexArgs,
|
|
13
14
|
} from '../types'
|
|
14
15
|
import { determineProofFormat, ensureDate, getAssertedValue, getAssertedValues } from '../utils'
|
|
15
|
-
import type { IOAuthStatusListImplementationResult, IStatusList } from './IStatusList'
|
|
16
|
+
import type { IExtractedCredentialDetails, IOAuthStatusListImplementationResult, IStatusList } from './IStatusList'
|
|
16
17
|
import { StatusList } from '@sd-jwt/jwt-status-list'
|
|
17
18
|
import type { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
18
19
|
import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
@@ -164,41 +165,92 @@ export class OAuthStatusListImplementation implements IStatusList {
|
|
|
164
165
|
return statusList.getStatus(index)
|
|
165
166
|
}
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Performs the initial parsing of a StatusListCredential.
|
|
170
|
+
* This method handles expensive operations like JWT/CWT decoding once.
|
|
171
|
+
* It extracts all details available from the credential payload itself.
|
|
172
|
+
*/
|
|
173
|
+
async extractCredentialDetails(credential: CompactJWT | CWT): Promise<IExtractedCredentialDetails> {
|
|
174
|
+
if (typeof credential !== 'string') {
|
|
175
|
+
return Promise.reject('statusListCredential must be a JWT or CWT string')
|
|
176
|
+
}
|
|
172
177
|
|
|
173
|
-
const
|
|
174
|
-
const
|
|
178
|
+
const proofFormat = determineProofFormat(credential)
|
|
179
|
+
const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(credential) : decodeStatusListCWT(credential)
|
|
175
180
|
|
|
176
181
|
return {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
encodedList: statusList.compressStatusList(),
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
length: statusList.statusList.length,
|
|
184
|
-
statusListCredential: statusListPayload,
|
|
185
|
-
statuslistContentType: this.buildContentType(proofFormat),
|
|
186
|
-
correlationId: args.correlationId, // FIXME these do not need to be inside the impl
|
|
187
|
-
driverType: args.driverType, // FIXME these do not need to be inside the impl
|
|
182
|
+
id: decoded.id,
|
|
183
|
+
issuer: decoded.issuer,
|
|
184
|
+
encodedList: decoded.statusList.compressStatusList(),
|
|
185
|
+
decodedPayload: decoded,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
188
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
// For CREATE and READ contexts
|
|
190
|
+
async toStatusListDetails(args: IToDetailsFromCredentialArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult>
|
|
191
|
+
// For UPDATE contexts
|
|
192
|
+
async toStatusListDetails(args: IMergeDetailsWithEntityArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult>
|
|
193
|
+
async toStatusListDetails(
|
|
194
|
+
args: IToDetailsFromCredentialArgs | IMergeDetailsWithEntityArgs,
|
|
195
|
+
): Promise<StatusListResult & IOAuthStatusListImplementationResult> {
|
|
196
|
+
if ('statusListCredential' in args) {
|
|
197
|
+
// CREATE/READ context
|
|
198
|
+
const { statusListCredential, bitsPerStatus, correlationId, driverType } = args
|
|
199
|
+
if (!bitsPerStatus || bitsPerStatus < 1) {
|
|
200
|
+
return Promise.reject(Error('bitsPerStatus must be set for OAuth status lists and must be 1 or higher'))
|
|
201
|
+
}
|
|
192
202
|
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
const proofFormat = determineProofFormat(statusListCredential as string)
|
|
204
|
+
const decoded =
|
|
205
|
+
proofFormat === 'jwt' ? decodeStatusListJWT(statusListCredential as string) : decodeStatusListCWT(statusListCredential as string)
|
|
206
|
+
const { statusList, issuer, id, exp } = decoded
|
|
207
|
+
const expiresAt = exp ? new Date(exp * 1000) : undefined
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
id,
|
|
211
|
+
encodedList: statusList.compressStatusList(),
|
|
212
|
+
issuer,
|
|
213
|
+
type: StatusListType.OAuthStatusList,
|
|
214
|
+
proofFormat,
|
|
215
|
+
length: statusList.statusList.length,
|
|
216
|
+
statusListCredential: statusListCredential as CompactJWT | CWT,
|
|
217
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
218
|
+
correlationId,
|
|
219
|
+
driverType,
|
|
195
220
|
bitsPerStatus,
|
|
196
221
|
...(expiresAt && { expiresAt }),
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
222
|
+
oauthStatusList: {
|
|
223
|
+
bitsPerStatus,
|
|
224
|
+
...(expiresAt && { expiresAt }),
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// UPDATE context
|
|
229
|
+
const { extractedDetails, statusListEntity } = args
|
|
230
|
+
const oauthEntity = statusListEntity as OAuthStatusListEntity
|
|
231
|
+
const decoded = extractedDetails.decodedPayload as { statusList: StatusList; exp?: number }
|
|
232
|
+
|
|
233
|
+
const proofFormat = determineProofFormat(statusListEntity.statusListCredential as string)
|
|
234
|
+
const expiresAt = decoded.exp ? new Date(decoded.exp * 1000) : undefined
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
id: extractedDetails.id,
|
|
238
|
+
encodedList: extractedDetails.encodedList,
|
|
239
|
+
issuer: extractedDetails.issuer,
|
|
240
|
+
type: StatusListType.OAuthStatusList,
|
|
241
|
+
proofFormat,
|
|
242
|
+
length: decoded.statusList.statusList.length,
|
|
243
|
+
statusListCredential: statusListEntity.statusListCredential!,
|
|
244
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
245
|
+
correlationId: statusListEntity.correlationId,
|
|
246
|
+
driverType: statusListEntity.driverType,
|
|
247
|
+
bitsPerStatus: oauthEntity.bitsPerStatus,
|
|
248
|
+
...(expiresAt && { expiresAt }),
|
|
249
|
+
oauthStatusList: {
|
|
250
|
+
bitsPerStatus: oauthEntity.bitsPerStatus,
|
|
251
|
+
...(expiresAt && { expiresAt }),
|
|
252
|
+
},
|
|
253
|
+
}
|
|
202
254
|
}
|
|
203
255
|
}
|
|
204
256
|
|
|
@@ -10,12 +10,13 @@ import {
|
|
|
10
10
|
} from '@sphereon/ssi-types'
|
|
11
11
|
|
|
12
12
|
import { StatusList } from '@sphereon/vc-status-list'
|
|
13
|
-
import type { IStatusList, IStatusList2021ImplementationResult } from './IStatusList'
|
|
13
|
+
import type { IExtractedCredentialDetails, IStatusList, IStatusList2021ImplementationResult } from './IStatusList'
|
|
14
14
|
import type {
|
|
15
15
|
CheckStatusIndexArgs,
|
|
16
16
|
CreateStatusListArgs,
|
|
17
|
+
IMergeDetailsWithEntityArgs,
|
|
18
|
+
IToDetailsFromCredentialArgs,
|
|
17
19
|
StatusListResult,
|
|
18
|
-
ToStatusListDetailsArgs,
|
|
19
20
|
UpdateStatusListFromEncodedListArgs,
|
|
20
21
|
UpdateStatusListIndexArgs,
|
|
21
22
|
} from '../types'
|
|
@@ -171,44 +172,87 @@ export class StatusList2021Implementation implements IStatusList {
|
|
|
171
172
|
return status ? Status2021.Invalid : Status2021.Valid
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Performs the initial parsing of a StatusListCredential.
|
|
177
|
+
* This method handles expensive operations like JWT/CWT decoding once.
|
|
178
|
+
* It extracts all details available from the credential payload itself.
|
|
179
|
+
*/
|
|
180
|
+
async extractCredentialDetails(credential: StatusListCredential): Promise<IExtractedCredentialDetails> {
|
|
181
|
+
const uniform = CredentialMapper.toUniformCredential(credential)
|
|
177
182
|
const { issuer, credentialSubject } = uniform
|
|
178
|
-
const
|
|
179
|
-
const encodedList = getAssertedProperty('encodedList', credentialSubject)
|
|
180
|
-
const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
|
|
181
|
-
|
|
182
|
-
const statusPurpose = getAssertedProperty('statusPurpose', credentialSubject)
|
|
183
|
-
const indexingDirection = 'rightToLeft'
|
|
184
|
-
const list = await StatusList.decode({ encodedList })
|
|
183
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
|
|
185
184
|
|
|
186
185
|
return {
|
|
187
|
-
|
|
188
|
-
id,
|
|
189
|
-
encodedList,
|
|
186
|
+
id: getAssertedValue('id', uniform.id),
|
|
190
187
|
issuer,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
statusListCredential: statusListPayload,
|
|
195
|
-
statuslistContentType: this.buildContentType(proofFormat),
|
|
196
|
-
correlationId: args.correlationId, // FIXME these do not need to be inside the impl
|
|
197
|
-
driverType: args.driverType, // FIXME these do not need to be inside the impl
|
|
198
|
-
|
|
199
|
-
// Flattened StatusList2021-specific fields
|
|
200
|
-
indexingDirection,
|
|
201
|
-
statusPurpose,
|
|
188
|
+
encodedList: getAssertedProperty('encodedList', subject),
|
|
189
|
+
}
|
|
190
|
+
}
|
|
202
191
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
async toStatusListDetails(args: IToDetailsFromCredentialArgs): Promise<StatusListResult & IStatusList2021ImplementationResult>
|
|
193
|
+
// For UPDATE contexts
|
|
194
|
+
async toStatusListDetails(args: IMergeDetailsWithEntityArgs): Promise<StatusListResult & IStatusList2021ImplementationResult>
|
|
195
|
+
async toStatusListDetails(
|
|
196
|
+
args: IToDetailsFromCredentialArgs | IMergeDetailsWithEntityArgs,
|
|
197
|
+
): Promise<StatusListResult & IStatusList2021ImplementationResult> {
|
|
198
|
+
if ('statusListCredential' in args) {
|
|
199
|
+
// CREATE/READ context
|
|
200
|
+
const { statusListCredential, correlationId, driverType } = args
|
|
201
|
+
const uniform = CredentialMapper.toUniformCredential(statusListCredential)
|
|
202
|
+
const { issuer, credentialSubject } = uniform
|
|
203
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
|
|
204
|
+
|
|
205
|
+
const id = getAssertedValue('id', uniform.id)
|
|
206
|
+
const encodedList = getAssertedProperty('encodedList', subject)
|
|
207
|
+
const statusPurpose = getAssertedProperty('statusPurpose', subject)
|
|
208
|
+
const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListCredential) === DocumentFormat.JWT ? 'jwt' : 'lds'
|
|
209
|
+
const list = await StatusList.decode({ encodedList })
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
id,
|
|
213
|
+
encodedList,
|
|
214
|
+
issuer,
|
|
215
|
+
type: StatusListType.StatusList2021,
|
|
216
|
+
proofFormat,
|
|
217
|
+
length: list.length,
|
|
218
|
+
statusListCredential,
|
|
219
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
220
|
+
correlationId,
|
|
221
|
+
driverType,
|
|
222
|
+
indexingDirection: 'rightToLeft',
|
|
206
223
|
statusPurpose,
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
224
|
+
statusList2021: {
|
|
225
|
+
indexingDirection: 'rightToLeft',
|
|
226
|
+
statusPurpose,
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
// UPDATE context
|
|
231
|
+
const { extractedDetails, statusListEntity } = args
|
|
232
|
+
const statusList2021Entity = statusListEntity as StatusList2021Entity
|
|
233
|
+
|
|
234
|
+
const proofFormat: CredentialProofFormat =
|
|
235
|
+
CredentialMapper.detectDocumentType(statusListEntity.statusListCredential!) === DocumentFormat.JWT ? 'jwt' : 'lds'
|
|
236
|
+
const list = await StatusList.decode({ encodedList: extractedDetails.encodedList })
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
id: extractedDetails.id,
|
|
240
|
+
encodedList: extractedDetails.encodedList,
|
|
241
|
+
issuer: extractedDetails.issuer,
|
|
242
|
+
type: StatusListType.StatusList2021,
|
|
243
|
+
proofFormat,
|
|
244
|
+
length: list.length,
|
|
245
|
+
statusListCredential: statusListEntity.statusListCredential!,
|
|
246
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
247
|
+
correlationId: statusListEntity.correlationId,
|
|
248
|
+
driverType: statusListEntity.driverType,
|
|
249
|
+
indexingDirection: statusList2021Entity.indexingDirection,
|
|
250
|
+
statusPurpose: statusList2021Entity.statusPurpose,
|
|
251
|
+
statusList2021: {
|
|
252
|
+
indexingDirection: statusList2021Entity.indexingDirection,
|
|
253
|
+
statusPurpose: statusList2021Entity.statusPurpose,
|
|
254
|
+
},
|
|
255
|
+
}
|
|
212
256
|
}
|
|
213
257
|
}
|
|
214
258
|
|
package/src/index.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -19,6 +19,8 @@ import type { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'
|
|
|
19
19
|
import type { StatusListOpts } from '@sphereon/oid4vci-common'
|
|
20
20
|
import { BitstringStatusPurpose } from '@4sure-tech/vc-bitstring-status-lists'
|
|
21
21
|
import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
|
|
22
|
+
import { IExtractedCredentialDetails } from '../impl/IStatusList'
|
|
23
|
+
import { BitstringStatusListArgs, IStatusListEntity } from '@sphereon/ssi-sdk.data-store'
|
|
22
24
|
|
|
23
25
|
export enum StatusOAuth {
|
|
24
26
|
Valid = 0,
|
|
@@ -31,8 +33,6 @@ export enum Status2021 {
|
|
|
31
33
|
Invalid = 1,
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export type BitstringStatus = number
|
|
35
|
-
|
|
36
36
|
export type StatusList2021Args = {
|
|
37
37
|
indexingDirection: StatusListIndexingDirection
|
|
38
38
|
statusPurpose?: StatusPurpose2021
|
|
@@ -44,14 +44,6 @@ export type OAuthStatusListArgs = {
|
|
|
44
44
|
expiresAt?: Date
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export type BitstringStatusListArgs = {
|
|
48
|
-
statusPurpose: BitstringStatusPurpose
|
|
49
|
-
bitsPerStatus: number
|
|
50
|
-
ttl?: number
|
|
51
|
-
validFrom?: Date
|
|
52
|
-
validUntil?: Date
|
|
53
|
-
}
|
|
54
|
-
|
|
55
47
|
export type BaseCreateNewStatusListArgs = {
|
|
56
48
|
type: StatusListType
|
|
57
49
|
id: string
|
|
@@ -102,7 +94,7 @@ export interface UpdateStatusListFromStatusListCredentialArgs {
|
|
|
102
94
|
statusListCredential: StatusListCredential // | CompactJWT
|
|
103
95
|
keyRef?: string
|
|
104
96
|
statusListIndex: number | string
|
|
105
|
-
value: number | Status2021 | StatusOAuth
|
|
97
|
+
value: number | Status2021 | StatusOAuth
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
export interface StatusListResult {
|
|
@@ -117,20 +109,6 @@ export interface StatusListResult {
|
|
|
117
109
|
correlationId?: string
|
|
118
110
|
driverType?: StatusListDriverType
|
|
119
111
|
|
|
120
|
-
// Flattened StatusList2021 fields
|
|
121
|
-
indexingDirection?: StatusListIndexingDirection
|
|
122
|
-
statusPurpose?: StatusPurpose2021 | BitstringStatusPurpose | BitstringStatusPurpose[]
|
|
123
|
-
|
|
124
|
-
// Flattened OAuth fields
|
|
125
|
-
bitsPerStatus?: number
|
|
126
|
-
expiresAt?: Date
|
|
127
|
-
|
|
128
|
-
// Flattened Bitstring fields
|
|
129
|
-
validFrom?: Date
|
|
130
|
-
validUntil?: Date
|
|
131
|
-
ttl?: number
|
|
132
|
-
|
|
133
|
-
// Legacy nested structures for backward compatibility
|
|
134
112
|
statusList2021?: {
|
|
135
113
|
indexingDirection: StatusListIndexingDirection
|
|
136
114
|
statusPurpose: StatusPurpose2021
|
|
@@ -163,16 +141,6 @@ export interface StatusListOAuthEntryCredentialStatus extends ICredentialStatus
|
|
|
163
141
|
expiresAt?: Date
|
|
164
142
|
}
|
|
165
143
|
|
|
166
|
-
export interface BitstringStatusListEntryCredentialStatus extends ICredentialStatus {
|
|
167
|
-
type: 'BitstringStatusListEntry'
|
|
168
|
-
statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
|
|
169
|
-
statusListIndex: string
|
|
170
|
-
statusListCredential: string
|
|
171
|
-
bitsPerStatus?: number
|
|
172
|
-
statusMessage?: Array<BitstringStatus>
|
|
173
|
-
statusReference?: string | string[]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
144
|
export interface StatusList2021ToVerifiableCredentialArgs {
|
|
177
145
|
issuer: string | IIssuer
|
|
178
146
|
id: string
|
|
@@ -198,7 +166,7 @@ export interface CreateStatusListArgs {
|
|
|
198
166
|
export interface UpdateStatusListIndexArgs {
|
|
199
167
|
statusListCredential: StatusListCredential // | CompactJWT
|
|
200
168
|
statusListIndex: number | string
|
|
201
|
-
value: number | Status2021 | StatusOAuth
|
|
169
|
+
value: number | Status2021 | StatusOAuth
|
|
202
170
|
bitsPerStatus?: number
|
|
203
171
|
keyRef?: string
|
|
204
172
|
expiresAt?: Date
|
|
@@ -210,11 +178,22 @@ export interface CheckStatusIndexArgs {
|
|
|
210
178
|
bitsPerStatus?: number
|
|
211
179
|
}
|
|
212
180
|
|
|
213
|
-
|
|
214
|
-
|
|
181
|
+
// For the CREATE and READ contexts
|
|
182
|
+
export interface IToDetailsFromCredentialArgs {
|
|
183
|
+
// The source credential we are converting
|
|
184
|
+
statusListCredential: StatusListCredential
|
|
185
|
+
|
|
186
|
+
// The required metadata that is NOT in the credential itself
|
|
187
|
+
statusListType: StatusListType
|
|
188
|
+
bitsPerStatus?: number
|
|
215
189
|
correlationId?: string
|
|
216
190
|
driverType?: StatusListDriverType
|
|
217
|
-
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// For the UPDATE context
|
|
194
|
+
export interface IMergeDetailsWithEntityArgs {
|
|
195
|
+
extractedDetails: IExtractedCredentialDetails
|
|
196
|
+
statusListEntity: IStatusListEntity
|
|
218
197
|
}
|
|
219
198
|
|
|
220
199
|
/**
|
package/src/utils.ts
CHANGED
|
@@ -53,31 +53,60 @@ export function assertValidProofType(type: StatusListType, proofFormat: Credenti
|
|
|
53
53
|
|
|
54
54
|
export function determineStatusListType(credential: StatusListCredential): StatusListType {
|
|
55
55
|
const proofFormat = determineProofFormat(credential)
|
|
56
|
+
|
|
56
57
|
switch (proofFormat) {
|
|
57
58
|
case 'jwt':
|
|
58
|
-
|
|
59
|
-
const keys = Object.keys(payload)
|
|
60
|
-
if (keys.includes('status_list')) {
|
|
61
|
-
return StatusListType.OAuthStatusList
|
|
62
|
-
} else if (keys.includes('vc')) {
|
|
63
|
-
return StatusListType.StatusList2021
|
|
64
|
-
}
|
|
65
|
-
break
|
|
59
|
+
return determineJwtStatusListType(credential as string)
|
|
66
60
|
case 'lds':
|
|
67
|
-
|
|
68
|
-
const type = uniform.type.find((t) => {
|
|
69
|
-
return Object.values(StatusListType).some((statusType) => t.includes(statusType))
|
|
70
|
-
})
|
|
71
|
-
if (!type) {
|
|
72
|
-
throw new Error('Invalid status list credential type')
|
|
73
|
-
}
|
|
74
|
-
return type.replace('Credential', '') as StatusListType
|
|
75
|
-
|
|
61
|
+
return determineLdsStatusListType(credential)
|
|
76
62
|
case 'cbor':
|
|
77
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')
|
|
78
96
|
}
|
|
79
97
|
|
|
80
|
-
|
|
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
|
+
}
|
|
81
110
|
}
|
|
82
111
|
|
|
83
112
|
export function determineProofFormat(credential: StatusListCredential): CredentialProofFormat {
|