@sd-jwt/sd-jwt-vc 0.14.2-next.0 → 0.15.0
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/CHANGELOG.md +11 -0
- package/README.md +2 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -5
- package/dist/index.mjs +8 -5
- package/package.json +7 -7
- package/src/sd-jwt-vc-config.ts +3 -1
- package/src/sd-jwt-vc-instance.ts +5 -1
- package/src/test/index.spec.ts +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.15.0](https://github.com/openwallet-foundation-labs/sd-jwt-js/compare/v0.14.1...v0.15.0) (2025-08-20)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Allows to pass a custom function for the status list JWT validation ([#306](https://github.com/openwallet-foundation-labs/sd-jwt-js/issues/306)) ([25e546e](https://github.com/openwallet-foundation-labs/sd-jwt-js/commit/25e546e1536178f8ee41b0e1b3836656fd6f48ab))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [0.14.1](https://github.com/openwallet-foundation-labs/sd-jwt-js/compare/v0.14.0...v0.14.1) (2025-08-02)
|
|
7
18
|
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -87,6 +87,8 @@ Check out more details in our [documentation](https://github.com/openwallet-foun
|
|
|
87
87
|
|
|
88
88
|
To add revocation capabilities, you can use the `@sd-jwt/jwt-status-list` library to create a JWT Status List and include it in the SD-JWT-VC.
|
|
89
89
|
|
|
90
|
+
You can pass a dedicated `statusVerifier` function in the configuration to verify the signature of the payload of the JWT of the statuslist. If no function is provided, it will fallback to the verifier that is also used for the sd-jwt-vc.
|
|
91
|
+
|
|
90
92
|
### Type Metadata
|
|
91
93
|
|
|
92
94
|
By setting the `loadTypeMetadataFormat` to `true` like this:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
1
|
+
import { SDJWTConfig, Verifier, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
2
2
|
import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -156,6 +156,7 @@ type SDJWTVCConfig = SDJWTConfig & {
|
|
|
156
156
|
statusListFetcher?: StatusListFetcher;
|
|
157
157
|
statusValidator?: StatusValidator;
|
|
158
158
|
vctFetcher?: VcTFetcher;
|
|
159
|
+
statusVerifier?: Verifier;
|
|
159
160
|
loadTypeMetadataFormat?: boolean;
|
|
160
161
|
timeout?: number;
|
|
161
162
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
1
|
+
import { SDJWTConfig, Verifier, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
|
|
2
2
|
import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -156,6 +156,7 @@ type SDJWTVCConfig = SDJWTConfig & {
|
|
|
156
156
|
statusListFetcher?: StatusListFetcher;
|
|
157
157
|
statusValidator?: StatusValidator;
|
|
158
158
|
vctFetcher?: VcTFetcher;
|
|
159
|
+
statusVerifier?: Verifier;
|
|
159
160
|
loadTypeMetadataFormat?: boolean;
|
|
160
161
|
timeout?: number;
|
|
161
162
|
};
|
package/dist/index.js
CHANGED
|
@@ -325,7 +325,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
325
325
|
*/
|
|
326
326
|
verifyStatus(result, options) {
|
|
327
327
|
return __async(this, null, function* () {
|
|
328
|
-
var _a, _b, _c, _d;
|
|
328
|
+
var _a, _b, _c, _d, _e;
|
|
329
329
|
if (result.payload.status) {
|
|
330
330
|
if (result.payload.status.status_list) {
|
|
331
331
|
const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
|
|
@@ -333,16 +333,19 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
|
|
|
333
333
|
result.payload.status.status_list.uri
|
|
334
334
|
);
|
|
335
335
|
const slJWT = import_core.Jwt.fromEncode(statusListJWT);
|
|
336
|
-
yield slJWT.verify(
|
|
337
|
-
|
|
338
|
-
|
|
336
|
+
yield slJWT.verify(
|
|
337
|
+
(_b = this.userConfig.statusVerifier) != null ? _b : this.userConfig.verifier,
|
|
338
|
+
options
|
|
339
|
+
);
|
|
340
|
+
const currentDate = (_c = options == null ? void 0 : options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
|
|
341
|
+
if (((_d = slJWT.payload) == null ? void 0 : _d.exp) && slJWT.payload.exp < currentDate) {
|
|
339
342
|
throw new import_utils.SDJWTException("Status list is expired");
|
|
340
343
|
}
|
|
341
344
|
const statusList = (0, import_jwt_status_list.getListFromStatusListJWT)(statusListJWT);
|
|
342
345
|
const status = statusList.getStatus(
|
|
343
346
|
result.payload.status.status_list.idx
|
|
344
347
|
);
|
|
345
|
-
const statusValidator = (
|
|
348
|
+
const statusValidator = (_e = this.userConfig.statusValidator) != null ? _e : this.statusValidator.bind(this);
|
|
346
349
|
yield statusValidator(status);
|
|
347
350
|
}
|
|
348
351
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -293,7 +293,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
293
293
|
*/
|
|
294
294
|
verifyStatus(result, options) {
|
|
295
295
|
return __async(this, null, function* () {
|
|
296
|
-
var _a, _b, _c, _d;
|
|
296
|
+
var _a, _b, _c, _d, _e;
|
|
297
297
|
if (result.payload.status) {
|
|
298
298
|
if (result.payload.status.status_list) {
|
|
299
299
|
const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
|
|
@@ -301,16 +301,19 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
|
|
|
301
301
|
result.payload.status.status_list.uri
|
|
302
302
|
);
|
|
303
303
|
const slJWT = Jwt.fromEncode(statusListJWT);
|
|
304
|
-
yield slJWT.verify(
|
|
305
|
-
|
|
306
|
-
|
|
304
|
+
yield slJWT.verify(
|
|
305
|
+
(_b = this.userConfig.statusVerifier) != null ? _b : this.userConfig.verifier,
|
|
306
|
+
options
|
|
307
|
+
);
|
|
308
|
+
const currentDate = (_c = options == null ? void 0 : options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
|
|
309
|
+
if (((_d = slJWT.payload) == null ? void 0 : _d.exp) && slJWT.payload.exp < currentDate) {
|
|
307
310
|
throw new SDJWTException("Status list is expired");
|
|
308
311
|
}
|
|
309
312
|
const statusList = getListFromStatusListJWT(statusListJWT);
|
|
310
313
|
const status = statusList.getStatus(
|
|
311
314
|
result.payload.status.status_list.idx
|
|
312
315
|
);
|
|
313
|
-
const statusValidator = (
|
|
316
|
+
const statusValidator = (_e = this.userConfig.statusValidator) != null ? _e : this.statusValidator.bind(this);
|
|
314
317
|
yield statusValidator(status);
|
|
315
318
|
}
|
|
316
319
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sd-jwt/sd-jwt-vc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
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.
|
|
43
|
-
"@sd-jwt/jwt-status-list": "0.
|
|
44
|
-
"@sd-jwt/utils": "0.
|
|
42
|
+
"@sd-jwt/core": "0.15.0",
|
|
43
|
+
"@sd-jwt/jwt-status-list": "0.15.0",
|
|
44
|
+
"@sd-jwt/utils": "0.15.0",
|
|
45
45
|
"ajv": "^8.17.1",
|
|
46
46
|
"ajv-formats": "^3.0.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@sd-jwt/crypto-nodejs": "0.
|
|
50
|
-
"@sd-jwt/types": "0.
|
|
49
|
+
"@sd-jwt/crypto-nodejs": "0.15.0",
|
|
50
|
+
"@sd-jwt/types": "0.15.0",
|
|
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": "b8733bc33817900b2bfe946bd10e3ff8673bb5fc"
|
|
71
71
|
}
|
package/src/sd-jwt-vc-config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SDJWTConfig } from '@sd-jwt/types';
|
|
1
|
+
import type { SDJWTConfig, Verifier } from '@sd-jwt/types';
|
|
2
2
|
import type { VcTFetcher } from './sd-jwt-vc-vct';
|
|
3
3
|
|
|
4
4
|
export type StatusListFetcher = (uri: string) => Promise<string>;
|
|
@@ -14,6 +14,8 @@ export type SDJWTVCConfig = SDJWTConfig & {
|
|
|
14
14
|
statusValidator?: StatusValidator;
|
|
15
15
|
// a function that fetches the type metadata format from the uri. If not provided, the library will assume that the response is a TypeMetadataFormat. Caching has to be implemented in this function. If the integrity value is passed, it to be validated according to https://www.w3.org/TR/SRI/
|
|
16
16
|
vctFetcher?: VcTFetcher;
|
|
17
|
+
// a function that verifies the status of the JWT. If not provided, the library will assume that the status is valid if it is 0.
|
|
18
|
+
statusVerifier?: Verifier;
|
|
17
19
|
// if set to true, it will load the metadata format based on the vct value. If not provided, it will default to false.
|
|
18
20
|
loadTypeMetadataFormat?: boolean;
|
|
19
21
|
// timeout value in milliseconds when to abort the fetch request. If not provided, it will default to 10000.
|
|
@@ -358,7 +358,11 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
|
|
|
358
358
|
StatusListJWTPayload
|
|
359
359
|
>(statusListJWT);
|
|
360
360
|
// check if the status list has a valid signature. The presence of the verifier is checked in the parent class.
|
|
361
|
-
await slJWT.verify(
|
|
361
|
+
await slJWT.verify(
|
|
362
|
+
this.userConfig.statusVerifier ??
|
|
363
|
+
(this.userConfig.verifier as Verifier),
|
|
364
|
+
options,
|
|
365
|
+
);
|
|
362
366
|
|
|
363
367
|
const currentDate =
|
|
364
368
|
options?.currentDate ?? Math.floor(Date.now() / 1000);
|
package/src/test/index.spec.ts
CHANGED
|
@@ -22,6 +22,10 @@ const iat = Math.floor(Date.now() / 1000);
|
|
|
22
22
|
|
|
23
23
|
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
|
|
24
24
|
|
|
25
|
+
//create a separate keypair for the status list
|
|
26
|
+
const { privateKey: statusListPrivateKey, publicKey: statusListPublicKey } =
|
|
27
|
+
Crypto.generateKeyPairSync('ed25519');
|
|
28
|
+
|
|
25
29
|
//TODO: to simulate a hosted status list, use the same appraoch as in vct.spec.ts
|
|
26
30
|
|
|
27
31
|
const createSignerVerifier = () => {
|
|
@@ -54,7 +58,7 @@ const generateStatusList = async (): Promise<string> => {
|
|
|
54
58
|
const values = createHeaderAndPayload(statusList, payload, header);
|
|
55
59
|
return new SignJWT(values.payload)
|
|
56
60
|
.setProtectedHeader(values.header)
|
|
57
|
-
.sign(
|
|
61
|
+
.sign(statusListPrivateKey);
|
|
58
62
|
};
|
|
59
63
|
|
|
60
64
|
const statusListJWT = await generateStatusList();
|
|
@@ -105,6 +109,15 @@ describe('Revocation', () => {
|
|
|
105
109
|
// if (status === 0) return Promise.resolve();
|
|
106
110
|
// throw new Error('Status is not valid');
|
|
107
111
|
// },
|
|
112
|
+
statusVerifier: async (data: string, sig: string) => {
|
|
113
|
+
//we could also look into the data to extract the public key from the x5c when provided
|
|
114
|
+
return Crypto.verify(
|
|
115
|
+
null,
|
|
116
|
+
Buffer.from(data),
|
|
117
|
+
statusListPublicKey,
|
|
118
|
+
Buffer.from(sig, 'base64url'),
|
|
119
|
+
);
|
|
120
|
+
},
|
|
108
121
|
});
|
|
109
122
|
|
|
110
123
|
test('Test with a non revcoked credential', async () => {
|