@sd-jwt/sd-jwt-vc 0.12.1-next.2 → 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 CHANGED
@@ -254,6 +254,12 @@ 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
package/dist/index.d.ts CHANGED
@@ -254,6 +254,12 @@ 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
package/dist/index.js CHANGED
@@ -281,14 +281,43 @@ 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
- const fetcher = (_a = this.userConfig.vctFetcher) != null ? _a : (uri, integrity) => this.fetch(uri, integrity);
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
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";
@@ -249,14 +249,43 @@ 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
- const fetcher = (_a = this.userConfig.vctFetcher) != null ? _a : (uri, integrity) => this.fetch(uri, integrity);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-jwt/sd-jwt-vc",
3
- "version": "0.12.1-next.2+1eefb26",
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.2+1eefb26",
43
- "@sd-jwt/jwt-status-list": "0.12.1-next.2+1eefb26",
44
- "@sd-jwt/utils": "0.12.1-next.2+1eefb26",
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.2+1eefb26",
50
- "@sd-jwt/types": "0.12.1-next.2+1eefb26",
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": "1eefb262c40ea23e999cdef6e75222e5b4df1e2c"
70
+ "gitHead": "f89ba445aeb57ce342ec76b58a0eb6d0c090a4e9"
71
71
  }
@@ -1,6 +1,6 @@
1
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,
@@ -294,12 +294,50 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
294
294
  throw new SDJWTException('vct claim is required');
295
295
  }
296
296
 
297
+ if (result.header?.vctm) {
298
+ return this.fetchVctFromHeader(result.payload.vct, result);
299
+ }
300
+
297
301
  const fetcher: VcTFetcher =
298
302
  this.userConfig.vctFetcher ??
299
303
  ((uri, integrity) => this.fetch(uri, integrity));
300
304
  return fetcher(result.payload.vct, result.payload['vct#Integrity']);
301
305
  }
302
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
+
303
341
  /**
304
342
  * Verifies the status of the SD-JWT-VC.
305
343
  * @param result
@@ -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 = {