@sd-jwt/sd-jwt-vc 0.12.1-next.1 → 0.12.1-next.3
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.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +41 -11
- package/dist/index.mjs +42 -12
- package/package.json +7 -7
- package/src/sd-jwt-vc-instance.ts +48 -7
- package/src/test/vct.spec.ts +31 -9
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
2
|
-
import { SdJwtPayload, SDJwtInstance } from '@sd-jwt/core';
|
|
2
|
+
import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Logo metadata used in rendering a credential.
|
|
@@ -217,7 +217,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
217
217
|
* Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
|
|
218
218
|
* @param currentDate current time in seconds
|
|
219
219
|
*/
|
|
220
|
-
verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean,
|
|
220
|
+
verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, options?: VerifierOptions): Promise<VerificationResult>;
|
|
221
221
|
/**
|
|
222
222
|
* Gets VCT Metadata of the raw SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC is invalid or does not contain a vct claim, an error is thrown.
|
|
223
223
|
* @param encodedSDJwt
|
|
@@ -254,10 +254,16 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
254
254
|
* @returns
|
|
255
255
|
*/
|
|
256
256
|
private fetchVct;
|
|
257
|
+
/**
|
|
258
|
+
* Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
|
|
259
|
+
* @param result
|
|
260
|
+
* @param
|
|
261
|
+
*/
|
|
262
|
+
private fetchVctFromHeader;
|
|
257
263
|
/**
|
|
258
264
|
* Verifies the status of the SD-JWT-VC.
|
|
259
265
|
* @param result
|
|
260
|
-
* @param
|
|
266
|
+
* @param options
|
|
261
267
|
*/
|
|
262
268
|
private verifyStatus;
|
|
263
269
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
2
|
-
import { SdJwtPayload, SDJwtInstance } from '@sd-jwt/core';
|
|
2
|
+
import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Logo metadata used in rendering a credential.
|
|
@@ -217,7 +217,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
217
217
|
* Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
|
|
218
218
|
* @param currentDate current time in seconds
|
|
219
219
|
*/
|
|
220
|
-
verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean,
|
|
220
|
+
verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, options?: VerifierOptions): Promise<VerificationResult>;
|
|
221
221
|
/**
|
|
222
222
|
* Gets VCT Metadata of the raw SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC is invalid or does not contain a vct claim, an error is thrown.
|
|
223
223
|
* @param encodedSDJwt
|
|
@@ -254,10 +254,16 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
254
254
|
* @returns
|
|
255
255
|
*/
|
|
256
256
|
private fetchVct;
|
|
257
|
+
/**
|
|
258
|
+
* Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
|
|
259
|
+
* @param result
|
|
260
|
+
* @param
|
|
261
|
+
*/
|
|
262
|
+
private fetchVctFromHeader;
|
|
257
263
|
/**
|
|
258
264
|
* Verifies the status of the SD-JWT-VC.
|
|
259
265
|
* @param result
|
|
260
|
-
* @param
|
|
266
|
+
* @param options
|
|
261
267
|
*/
|
|
262
268
|
private verifyStatus;
|
|
263
269
|
}
|
package/dist/index.js
CHANGED
|
@@ -131,8 +131,8 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
131
131
|
* Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
|
|
132
132
|
* @param currentDate current time in seconds
|
|
133
133
|
*/
|
|
134
|
-
verify(
|
|
135
|
-
return __async(this,
|
|
134
|
+
verify(encodedSDJwt, requiredClaimKeys, requireKeyBindings, options) {
|
|
135
|
+
return __async(this, null, function* () {
|
|
136
136
|
const result = yield __superGet(_SDJwtVcInstance.prototype, this, "verify").call(this, encodedSDJwt, requiredClaimKeys, requireKeyBindings).then((res) => {
|
|
137
137
|
return {
|
|
138
138
|
payload: res.payload,
|
|
@@ -140,7 +140,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
140
140
|
kb: res.kb
|
|
141
141
|
};
|
|
142
142
|
});
|
|
143
|
-
yield this.verifyStatus(result,
|
|
143
|
+
yield this.verifyStatus(result, options);
|
|
144
144
|
if (this.userConfig.loadTypeMetadataFormat) {
|
|
145
145
|
yield this.verifyVct(result);
|
|
146
146
|
}
|
|
@@ -281,22 +281,51 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
281
281
|
*/
|
|
282
282
|
fetchVct(result) {
|
|
283
283
|
return __async(this, null, function* () {
|
|
284
|
-
var _a;
|
|
284
|
+
var _a, _b;
|
|
285
285
|
if (!result.payload.vct) {
|
|
286
286
|
throw new import_utils.SDJWTException("vct claim is required");
|
|
287
287
|
}
|
|
288
|
-
|
|
288
|
+
if ((_a = result.header) == null ? void 0 : _a.vctm) {
|
|
289
|
+
return this.fetchVctFromHeader(result.payload.vct, result);
|
|
290
|
+
}
|
|
291
|
+
const fetcher = (_b = this.userConfig.vctFetcher) != null ? _b : (uri, integrity) => this.fetch(uri, integrity);
|
|
289
292
|
return fetcher(result.payload.vct, result.payload["vct#Integrity"]);
|
|
290
293
|
});
|
|
291
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
|
|
297
|
+
* @param result
|
|
298
|
+
* @param
|
|
299
|
+
*/
|
|
300
|
+
fetchVctFromHeader(vct, result) {
|
|
301
|
+
return __async(this, null, function* () {
|
|
302
|
+
var _a;
|
|
303
|
+
const vctmHeader = (_a = result.header) == null ? void 0 : _a.vctm;
|
|
304
|
+
if (!vctmHeader || !Array.isArray(vctmHeader)) {
|
|
305
|
+
throw new Error("vctm claim in SD JWT header is invalid");
|
|
306
|
+
}
|
|
307
|
+
const typeMetadataFormat = vctmHeader.map((vctm) => {
|
|
308
|
+
if (!(typeof vctm === "string")) {
|
|
309
|
+
throw new Error("vctm claim in SD JWT header is invalid");
|
|
310
|
+
}
|
|
311
|
+
return JSON.parse((0, import_utils.base64urlDecode)(vctm));
|
|
312
|
+
}).find((typeMetadataFormat2) => {
|
|
313
|
+
return typeMetadataFormat2.vct === vct;
|
|
314
|
+
});
|
|
315
|
+
if (!typeMetadataFormat) {
|
|
316
|
+
throw new Error("could not find VCT Metadata in JWT header");
|
|
317
|
+
}
|
|
318
|
+
return typeMetadataFormat;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
292
321
|
/**
|
|
293
322
|
* Verifies the status of the SD-JWT-VC.
|
|
294
323
|
* @param result
|
|
295
|
-
* @param
|
|
324
|
+
* @param options
|
|
296
325
|
*/
|
|
297
|
-
verifyStatus(result,
|
|
326
|
+
verifyStatus(result, options) {
|
|
298
327
|
return __async(this, null, function* () {
|
|
299
|
-
var _a, _b, _c;
|
|
328
|
+
var _a, _b, _c, _d;
|
|
300
329
|
if (result.payload.status) {
|
|
301
330
|
if (result.payload.status.status_list) {
|
|
302
331
|
const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
|
|
@@ -304,15 +333,16 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
304
333
|
result.payload.status.status_list.uri
|
|
305
334
|
);
|
|
306
335
|
const slJWT = import_core.Jwt.fromEncode(statusListJWT);
|
|
307
|
-
yield slJWT.verify(this.userConfig.verifier,
|
|
308
|
-
|
|
336
|
+
yield slJWT.verify(this.userConfig.verifier, options);
|
|
337
|
+
const currentDate = (_b = options == null ? void 0 : options.currentDate) != null ? _b : Math.floor(Date.now() / 1e3);
|
|
338
|
+
if (((_c = slJWT.payload) == null ? void 0 : _c.exp) && slJWT.payload.exp < currentDate) {
|
|
309
339
|
throw new import_utils.SDJWTException("Status list is expired");
|
|
310
340
|
}
|
|
311
341
|
const statusList = (0, import_jwt_status_list.getListFromStatusListJWT)(statusListJWT);
|
|
312
342
|
const status = statusList.getStatus(
|
|
313
343
|
result.payload.status.status_list.idx
|
|
314
344
|
);
|
|
315
|
-
const statusValidator = (
|
|
345
|
+
const statusValidator = (_d = this.userConfig.statusValidator) != null ? _d : this.statusValidator.bind(this);
|
|
316
346
|
yield statusValidator(status);
|
|
317
347
|
}
|
|
318
348
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -24,7 +24,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
24
24
|
|
|
25
25
|
// src/sd-jwt-vc-instance.ts
|
|
26
26
|
import { Jwt, SDJwt, SDJwtInstance } from "@sd-jwt/core";
|
|
27
|
-
import { SDJWTException } from "@sd-jwt/utils";
|
|
27
|
+
import { base64urlDecode, SDJWTException } from "@sd-jwt/utils";
|
|
28
28
|
import {
|
|
29
29
|
getListFromStatusListJWT
|
|
30
30
|
} from "@sd-jwt/jwt-status-list";
|
|
@@ -99,8 +99,8 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
99
99
|
* Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
|
|
100
100
|
* @param currentDate current time in seconds
|
|
101
101
|
*/
|
|
102
|
-
verify(
|
|
103
|
-
return __async(this,
|
|
102
|
+
verify(encodedSDJwt, requiredClaimKeys, requireKeyBindings, options) {
|
|
103
|
+
return __async(this, null, function* () {
|
|
104
104
|
const result = yield __superGet(_SDJwtVcInstance.prototype, this, "verify").call(this, encodedSDJwt, requiredClaimKeys, requireKeyBindings).then((res) => {
|
|
105
105
|
return {
|
|
106
106
|
payload: res.payload,
|
|
@@ -108,7 +108,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
108
108
|
kb: res.kb
|
|
109
109
|
};
|
|
110
110
|
});
|
|
111
|
-
yield this.verifyStatus(result,
|
|
111
|
+
yield this.verifyStatus(result, options);
|
|
112
112
|
if (this.userConfig.loadTypeMetadataFormat) {
|
|
113
113
|
yield this.verifyVct(result);
|
|
114
114
|
}
|
|
@@ -249,22 +249,51 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
249
249
|
*/
|
|
250
250
|
fetchVct(result) {
|
|
251
251
|
return __async(this, null, function* () {
|
|
252
|
-
var _a;
|
|
252
|
+
var _a, _b;
|
|
253
253
|
if (!result.payload.vct) {
|
|
254
254
|
throw new SDJWTException("vct claim is required");
|
|
255
255
|
}
|
|
256
|
-
|
|
256
|
+
if ((_a = result.header) == null ? void 0 : _a.vctm) {
|
|
257
|
+
return this.fetchVctFromHeader(result.payload.vct, result);
|
|
258
|
+
}
|
|
259
|
+
const fetcher = (_b = this.userConfig.vctFetcher) != null ? _b : (uri, integrity) => this.fetch(uri, integrity);
|
|
257
260
|
return fetcher(result.payload.vct, result.payload["vct#Integrity"]);
|
|
258
261
|
});
|
|
259
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
|
|
265
|
+
* @param result
|
|
266
|
+
* @param
|
|
267
|
+
*/
|
|
268
|
+
fetchVctFromHeader(vct, result) {
|
|
269
|
+
return __async(this, null, function* () {
|
|
270
|
+
var _a;
|
|
271
|
+
const vctmHeader = (_a = result.header) == null ? void 0 : _a.vctm;
|
|
272
|
+
if (!vctmHeader || !Array.isArray(vctmHeader)) {
|
|
273
|
+
throw new Error("vctm claim in SD JWT header is invalid");
|
|
274
|
+
}
|
|
275
|
+
const typeMetadataFormat = vctmHeader.map((vctm) => {
|
|
276
|
+
if (!(typeof vctm === "string")) {
|
|
277
|
+
throw new Error("vctm claim in SD JWT header is invalid");
|
|
278
|
+
}
|
|
279
|
+
return JSON.parse(base64urlDecode(vctm));
|
|
280
|
+
}).find((typeMetadataFormat2) => {
|
|
281
|
+
return typeMetadataFormat2.vct === vct;
|
|
282
|
+
});
|
|
283
|
+
if (!typeMetadataFormat) {
|
|
284
|
+
throw new Error("could not find VCT Metadata in JWT header");
|
|
285
|
+
}
|
|
286
|
+
return typeMetadataFormat;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
260
289
|
/**
|
|
261
290
|
* Verifies the status of the SD-JWT-VC.
|
|
262
291
|
* @param result
|
|
263
|
-
* @param
|
|
292
|
+
* @param options
|
|
264
293
|
*/
|
|
265
|
-
verifyStatus(result,
|
|
294
|
+
verifyStatus(result, options) {
|
|
266
295
|
return __async(this, null, function* () {
|
|
267
|
-
var _a, _b, _c;
|
|
296
|
+
var _a, _b, _c, _d;
|
|
268
297
|
if (result.payload.status) {
|
|
269
298
|
if (result.payload.status.status_list) {
|
|
270
299
|
const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
|
|
@@ -272,15 +301,16 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
272
301
|
result.payload.status.status_list.uri
|
|
273
302
|
);
|
|
274
303
|
const slJWT = Jwt.fromEncode(statusListJWT);
|
|
275
|
-
yield slJWT.verify(this.userConfig.verifier,
|
|
276
|
-
|
|
304
|
+
yield slJWT.verify(this.userConfig.verifier, options);
|
|
305
|
+
const currentDate = (_b = options == null ? void 0 : options.currentDate) != null ? _b : Math.floor(Date.now() / 1e3);
|
|
306
|
+
if (((_c = slJWT.payload) == null ? void 0 : _c.exp) && slJWT.payload.exp < currentDate) {
|
|
277
307
|
throw new SDJWTException("Status list is expired");
|
|
278
308
|
}
|
|
279
309
|
const statusList = getListFromStatusListJWT(statusListJWT);
|
|
280
310
|
const status = statusList.getStatus(
|
|
281
311
|
result.payload.status.status_list.idx
|
|
282
312
|
);
|
|
283
|
-
const statusValidator = (
|
|
313
|
+
const statusValidator = (_d = this.userConfig.statusValidator) != null ? _d : this.statusValidator.bind(this);
|
|
284
314
|
yield statusValidator(status);
|
|
285
315
|
}
|
|
286
316
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sd-jwt/sd-jwt-vc",
|
|
3
|
-
"version": "0.12.1-next.
|
|
3
|
+
"version": "0.12.1-next.3+f89ba44",
|
|
4
4
|
"description": "sd-jwt draft 7 implementation in typescript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
},
|
|
40
40
|
"license": "Apache-2.0",
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@sd-jwt/core": "0.12.1-next.
|
|
43
|
-
"@sd-jwt/jwt-status-list": "0.12.1-next.
|
|
44
|
-
"@sd-jwt/utils": "0.12.1-next.
|
|
42
|
+
"@sd-jwt/core": "0.12.1-next.3+f89ba44",
|
|
43
|
+
"@sd-jwt/jwt-status-list": "0.12.1-next.3+f89ba44",
|
|
44
|
+
"@sd-jwt/utils": "0.12.1-next.3+f89ba44",
|
|
45
45
|
"ajv": "^8.17.1",
|
|
46
46
|
"ajv-formats": "^3.0.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@sd-jwt/crypto-nodejs": "0.12.1-next.
|
|
50
|
-
"@sd-jwt/types": "0.12.1-next.
|
|
49
|
+
"@sd-jwt/crypto-nodejs": "0.12.1-next.3+f89ba44",
|
|
50
|
+
"@sd-jwt/types": "0.12.1-next.3+f89ba44",
|
|
51
51
|
"jose": "^5.2.2",
|
|
52
52
|
"msw": "^2.3.5"
|
|
53
53
|
},
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"esm"
|
|
68
68
|
]
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "f89ba445aeb57ce342ec76b58a0eb6d0c090a4e9"
|
|
71
71
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Jwt, SDJwt, SDJwtInstance } from '@sd-jwt/core';
|
|
1
|
+
import { Jwt, SDJwt, SDJwtInstance, type VerifierOptions } from '@sd-jwt/core';
|
|
2
2
|
import type { DisclosureFrame, Hasher, Verifier } from '@sd-jwt/types';
|
|
3
|
-
import { SDJWTException } from '@sd-jwt/utils';
|
|
3
|
+
import { base64urlDecode, SDJWTException } from '@sd-jwt/utils';
|
|
4
4
|
import type { SdJwtVcPayload } from './sd-jwt-vc-payload';
|
|
5
5
|
import type {
|
|
6
6
|
SDJWTVCConfig,
|
|
@@ -110,9 +110,10 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
110
110
|
*/
|
|
111
111
|
async verify(
|
|
112
112
|
encodedSDJwt: string,
|
|
113
|
+
//TODO: we need to move these values in options, causing a breaking change
|
|
113
114
|
requiredClaimKeys?: string[],
|
|
114
115
|
requireKeyBindings?: boolean,
|
|
115
|
-
|
|
116
|
+
options?: VerifierOptions,
|
|
116
117
|
) {
|
|
117
118
|
// Call the parent class's verify method
|
|
118
119
|
const result: VerificationResult = await super
|
|
@@ -125,7 +126,7 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
125
126
|
};
|
|
126
127
|
});
|
|
127
128
|
|
|
128
|
-
await this.verifyStatus(result,
|
|
129
|
+
await this.verifyStatus(result, options);
|
|
129
130
|
if (this.userConfig.loadTypeMetadataFormat) {
|
|
130
131
|
await this.verifyVct(result);
|
|
131
132
|
}
|
|
@@ -293,20 +294,58 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
293
294
|
throw new SDJWTException('vct claim is required');
|
|
294
295
|
}
|
|
295
296
|
|
|
297
|
+
if (result.header?.vctm) {
|
|
298
|
+
return this.fetchVctFromHeader(result.payload.vct, result);
|
|
299
|
+
}
|
|
300
|
+
|
|
296
301
|
const fetcher: VcTFetcher =
|
|
297
302
|
this.userConfig.vctFetcher ??
|
|
298
303
|
((uri, integrity) => this.fetch(uri, integrity));
|
|
299
304
|
return fetcher(result.payload.vct, result.payload['vct#Integrity']);
|
|
300
305
|
}
|
|
301
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
|
|
309
|
+
* @param result
|
|
310
|
+
* @param
|
|
311
|
+
*/
|
|
312
|
+
private async fetchVctFromHeader(
|
|
313
|
+
vct: string,
|
|
314
|
+
result: VerificationResult,
|
|
315
|
+
): Promise<TypeMetadataFormat> {
|
|
316
|
+
const vctmHeader = result.header?.vctm;
|
|
317
|
+
|
|
318
|
+
if (!vctmHeader || !Array.isArray(vctmHeader)) {
|
|
319
|
+
throw new Error('vctm claim in SD JWT header is invalid');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const typeMetadataFormat = (vctmHeader as unknown[])
|
|
323
|
+
.map((vctm) => {
|
|
324
|
+
if (!(typeof vctm === 'string')) {
|
|
325
|
+
throw new Error('vctm claim in SD JWT header is invalid');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return JSON.parse(base64urlDecode(vctm));
|
|
329
|
+
})
|
|
330
|
+
.find((typeMetadataFormat) => {
|
|
331
|
+
return typeMetadataFormat.vct === vct;
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
if (!typeMetadataFormat) {
|
|
335
|
+
throw new Error('could not find VCT Metadata in JWT header');
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return typeMetadataFormat;
|
|
339
|
+
}
|
|
340
|
+
|
|
302
341
|
/**
|
|
303
342
|
* Verifies the status of the SD-JWT-VC.
|
|
304
343
|
* @param result
|
|
305
|
-
* @param
|
|
344
|
+
* @param options
|
|
306
345
|
*/
|
|
307
346
|
private async verifyStatus(
|
|
308
347
|
result: VerificationResult,
|
|
309
|
-
|
|
348
|
+
options?: VerifierOptions,
|
|
310
349
|
): Promise<void> {
|
|
311
350
|
if (result.payload.status) {
|
|
312
351
|
//checks if a status field is present in the payload based on https://www.ietf.org/archive/id/draft-ietf-oauth-status-list-02.html
|
|
@@ -325,8 +364,10 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
325
364
|
StatusListJWTPayload
|
|
326
365
|
>(statusListJWT);
|
|
327
366
|
// check if the status list has a valid signature. The presence of the verifier is checked in the parent class.
|
|
328
|
-
await slJWT.verify(this.userConfig.verifier as Verifier,
|
|
367
|
+
await slJWT.verify(this.userConfig.verifier as Verifier, options);
|
|
329
368
|
|
|
369
|
+
const currentDate =
|
|
370
|
+
options?.currentDate ?? Math.floor(Date.now() / 1000);
|
|
330
371
|
//check if the status list is expired
|
|
331
372
|
if (slJWT.payload?.exp && (slJWT.payload.exp as number) < currentDate) {
|
|
332
373
|
throw new SDJWTException('Status list is expired');
|
package/src/test/vct.spec.ts
CHANGED
|
@@ -9,6 +9,16 @@ import { HttpResponse, http } from 'msw';
|
|
|
9
9
|
import { afterEach } from 'node:test';
|
|
10
10
|
import type { TypeMetadataFormat } from '../sd-jwt-vc-type-metadata-format';
|
|
11
11
|
|
|
12
|
+
const exampleVctm = {
|
|
13
|
+
vct: 'http://example.com/example',
|
|
14
|
+
name: 'ExampleCredentialType',
|
|
15
|
+
description: 'An example credential type',
|
|
16
|
+
schema_uri: 'http://example.com/schema/example',
|
|
17
|
+
//this value could be generated on demand to make it easier when changing the values
|
|
18
|
+
'schema_uri#Integrity':
|
|
19
|
+
'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
|
|
20
|
+
};
|
|
21
|
+
|
|
12
22
|
const restHandlers = [
|
|
13
23
|
http.get('http://example.com/schema/example', () => {
|
|
14
24
|
const res = {
|
|
@@ -42,15 +52,7 @@ const restHandlers = [
|
|
|
42
52
|
return HttpResponse.json(res);
|
|
43
53
|
}),
|
|
44
54
|
http.get('http://example.com/example', () => {
|
|
45
|
-
const res: TypeMetadataFormat =
|
|
46
|
-
vct: 'http://example.com/example',
|
|
47
|
-
name: 'ExampleCredentialType',
|
|
48
|
-
description: 'An example credential type',
|
|
49
|
-
schema_uri: 'http://example.com/schema/example',
|
|
50
|
-
//this value could be generated on demand to make it easier when changing the values
|
|
51
|
-
'schema_uri#Integrity':
|
|
52
|
-
'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
|
|
53
|
-
};
|
|
55
|
+
const res: TypeMetadataFormat = exampleVctm;
|
|
54
56
|
return HttpResponse.json(res);
|
|
55
57
|
}),
|
|
56
58
|
http.get('http://example.com/timeout', () => {
|
|
@@ -133,6 +135,26 @@ describe('App', () => {
|
|
|
133
135
|
await sdjwt.verify(encodedSdjwt);
|
|
134
136
|
});
|
|
135
137
|
|
|
138
|
+
test('VCT from JWT header Validation', async () => {
|
|
139
|
+
const expectedPayload: SdJwtVcPayload = {
|
|
140
|
+
iat,
|
|
141
|
+
iss,
|
|
142
|
+
vct,
|
|
143
|
+
'vct#Integrity': vctIntegrity,
|
|
144
|
+
...claims,
|
|
145
|
+
};
|
|
146
|
+
const header = {
|
|
147
|
+
vctm: [Buffer.from(JSON.stringify(exampleVctm)).toString('base64url')],
|
|
148
|
+
};
|
|
149
|
+
const encodedSdjwt = await sdjwt.issue(
|
|
150
|
+
expectedPayload,
|
|
151
|
+
disclosureFrame as unknown as DisclosureFrame<SdJwtVcPayload>,
|
|
152
|
+
{ header },
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
await sdjwt.verify(encodedSdjwt);
|
|
156
|
+
});
|
|
157
|
+
|
|
136
158
|
test('VCT Validation with timeout', async () => {
|
|
137
159
|
const vct = 'http://example.com/timeout';
|
|
138
160
|
const expectedPayload: SdJwtVcPayload = {
|