@sd-jwt/core 0.20.1 → 0.21.0-alpha-20260916100413

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.
Files changed (68) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +82 -80
  3. package/dist/index.cjs +1526 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +696 -0
  6. package/dist/index.d.mts +537 -527
  7. package/dist/index.mjs +1422 -1998
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +29 -49
  10. package/CHANGELOG.md +0 -39
  11. package/dist/index.d.ts +0 -686
  12. package/dist/index.js +0 -2100
  13. package/src/decode/decode.ts +0 -407
  14. package/src/decode/index.ts +0 -1
  15. package/src/decoy.ts +0 -15
  16. package/src/flattenJSON.ts +0 -99
  17. package/src/generalJSON.ts +0 -157
  18. package/src/index.ts +0 -1000
  19. package/src/jwt.ts +0 -286
  20. package/src/kbjwt.ts +0 -101
  21. package/src/present/index.ts +0 -1
  22. package/src/present/present.ts +0 -216
  23. package/src/sdjwt.ts +0 -384
  24. package/src/test/decode/decode.spec.ts +0 -197
  25. package/src/test/decoy.spec.ts +0 -30
  26. package/src/test/flattenJSON.spec.ts +0 -122
  27. package/src/test/generalJSON.spec.ts +0 -198
  28. package/src/test/index.spec.ts +0 -986
  29. package/src/test/jwt.spec.ts +0 -301
  30. package/src/test/kbjwt.spec.ts +0 -555
  31. package/src/test/pass.spec.ts +0 -7
  32. package/src/test/present/present.spec.ts +0 -305
  33. package/src/test/sdjwt.spec.ts +0 -384
  34. package/src/test/types/type.spec.ts +0 -88
  35. package/src/test/utils/base64url.spec.ts +0 -33
  36. package/src/test/utils/disclosure.spec.ts +0 -170
  37. package/src/test/utils/error.spec.ts +0 -15
  38. package/src/types/index.ts +0 -2
  39. package/src/types/type.ts +0 -270
  40. package/src/types/verification-error.ts +0 -55
  41. package/src/utils/base64url.ts +0 -6
  42. package/src/utils/disclosure.ts +0 -121
  43. package/src/utils/error.ts +0 -25
  44. package/src/utils/index.ts +0 -3
  45. package/src/utils/strict-json.ts +0 -17
  46. package/test/app-e2e.spec.ts +0 -292
  47. package/test/array_data_types.json +0 -31
  48. package/test/array_full_sd.json +0 -21
  49. package/test/array_in_sd.json +0 -13
  50. package/test/array_nested_in_plain.json +0 -29
  51. package/test/array_none_disclosed.json +0 -17
  52. package/test/array_of_nulls.json +0 -15
  53. package/test/array_of_objects.json +0 -65
  54. package/test/array_of_scalars.json +0 -19
  55. package/test/array_recursive_sd.json +0 -35
  56. package/test/array_recursive_sd_some_disclosed.json +0 -63
  57. package/test/complex.json +0 -43
  58. package/test/header_mod.json +0 -48
  59. package/test/json_serialization.json +0 -48
  60. package/test/key_binding.json +0 -48
  61. package/test/no_sd.json +0 -36
  62. package/test/object_data_types.json +0 -62
  63. package/test/recursions.json +0 -117
  64. package/test/rfc9901-audit-fixes.spec.ts +0 -252
  65. package/test/rfc9901-validation.spec.ts +0 -150
  66. package/test/tsconfig.json +0 -4
  67. package/tsconfig.json +0 -7
  68. package/vitest.config.mts +0 -4
package/dist/index.mjs CHANGED
@@ -1,2036 +1,1460 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- var __objRest = (source, exclude) => {
21
- var target = {};
22
- for (var prop in source)
23
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
- target[prop] = source[prop];
25
- if (source != null && __getOwnPropSymbols)
26
- for (var prop of __getOwnPropSymbols(source)) {
27
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
- target[prop] = source[prop];
29
- }
30
- return target;
31
- };
32
- var __async = (__this, __arguments, generator) => {
33
- return new Promise((resolve, reject) => {
34
- var fulfilled = (value) => {
35
- try {
36
- step(generator.next(value));
37
- } catch (e) {
38
- reject(e);
39
- }
40
- };
41
- var rejected = (value) => {
42
- try {
43
- step(generator.throw(value));
44
- } catch (e) {
45
- reject(e);
46
- }
47
- };
48
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
49
- step((generator = generator.apply(__this, __arguments)).next());
50
- });
51
- };
52
-
53
- // src/types/type.ts
54
- var SD_SEPARATOR = "~";
55
- var SD_LIST_KEY = "...";
56
- var SD_DIGEST = "_sd";
57
- var SD_DECOY = "_sd_decoy";
58
- var KB_JWT_TYP = "kb+jwt";
59
- var encodePathSegment = (segment) => segment.replace(/~/g, "~0").replace(/\./g, "~1");
60
- var encodePath = (segments) => segments.map(encodePathSegment).join(".");
61
- var IANA_HASH_ALGORITHMS = [
62
- "sha-256",
63
- "sha-256-128",
64
- "sha-256-120",
65
- "sha-256-96",
66
- "sha-256-64",
67
- "sha-256-32",
68
- "sha-384",
69
- "sha-512",
70
- "sha3-224",
71
- "sha3-256",
72
- "sha3-384",
73
- "sha3-512",
74
- "blake2s-256",
75
- "blake2b-256",
76
- "blake2b-512",
77
- "k12-256",
78
- "k12-512"
1
+ import { base64UrlToUint8Array, base64urlDecode, base64urlDecodeJson, base64urlEncode, decodeJwt as decodeJwt$1, nowInSeconds, uint8ArrayToBase64Url } from "@owf/identity-common";
2
+ //#region src/types/type.ts
3
+ const SD_SEPARATOR = "~";
4
+ const SD_LIST_KEY = "...";
5
+ const SD_DIGEST = "_sd";
6
+ const SD_DECOY = "_sd_decoy";
7
+ const KB_JWT_TYP = "kb+jwt";
8
+ const encodePathSegment = (segment) => segment.replace(/~/g, "~0").replace(/\./g, "~1");
9
+ const encodePath = (segments) => segments.map(encodePathSegment).join(".");
10
+ const IANA_HASH_ALGORITHMS = [
11
+ "sha-256",
12
+ "sha-256-128",
13
+ "sha-256-120",
14
+ "sha-256-96",
15
+ "sha-256-64",
16
+ "sha-256-32",
17
+ "sha-384",
18
+ "sha-512",
19
+ "sha3-224",
20
+ "sha3-256",
21
+ "sha3-384",
22
+ "sha3-512",
23
+ "blake2s-256",
24
+ "blake2b-256",
25
+ "blake2b-512",
26
+ "k12-256",
27
+ "k12-512"
79
28
  ];
80
- var DEFAULT_SECURE_HASH_ALGORITHMS = [
81
- "sha-256",
82
- "sha-384",
83
- "sha-512",
84
- "sha3-256",
85
- "sha3-384",
86
- "sha3-512",
87
- "blake2s-256",
88
- "blake2b-256",
89
- "blake2b-512",
90
- "k12-256",
91
- "k12-512"
29
+ const DEFAULT_SECURE_HASH_ALGORITHMS = [
30
+ "sha-256",
31
+ "sha-384",
32
+ "sha-512",
33
+ "sha3-256",
34
+ "sha3-384",
35
+ "sha3-512",
36
+ "blake2s-256",
37
+ "blake2b-256",
38
+ "blake2b-512",
39
+ "k12-256",
40
+ "k12-512"
92
41
  ];
93
-
94
- // src/utils/base64url.ts
95
- import {
96
- base64UrlToUint8Array,
97
- base64urlDecode,
98
- base64urlEncode,
99
- uint8ArrayToBase64Url
100
- } from "@owf/identity-common";
101
-
102
- // src/utils/error.ts
103
- var SDJWTException = class _SDJWTException extends Error {
104
- constructor(message, details) {
105
- super(message);
106
- Object.setPrototypeOf(this, _SDJWTException.prototype);
107
- this.name = "SDJWTException";
108
- this.details = details;
109
- }
110
- getFullMessage() {
111
- return `${this.name}: ${this.message} ${this.details ? `- ${JSON.stringify(this.details)}` : ""}`;
112
- }
42
+ //#endregion
43
+ //#region src/utils/error.ts
44
+ var SDJWTException = class SDJWTException extends Error {
45
+ constructor(message, details) {
46
+ super(message);
47
+ Object.setPrototypeOf(this, SDJWTException.prototype);
48
+ this.name = "SDJWTException";
49
+ this.details = details;
50
+ }
51
+ getFullMessage() {
52
+ return `${this.name}: ${this.message} ${this.details ? `- ${JSON.stringify(this.details)}` : ""}`;
53
+ }
113
54
  };
55
+ /**
56
+ * Narrows an unknown caught value to an Error instance.
57
+ */
114
58
  function ensureError(value) {
115
- if (value instanceof Error) return value;
116
- if (typeof value === "string") return new Error(value);
117
- return new Error(String(value));
59
+ if (value instanceof Error) return value;
60
+ if (typeof value === "string") return new Error(value);
61
+ return new Error(String(value));
118
62
  }
119
-
120
- // src/utils/strict-json.ts
121
- var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
122
- var decodeBase64urlJsonStrict = (encoded, errorMessage) => {
123
- try {
124
- const bytes = base64UrlToUint8Array(encoded);
125
- const decoded = utf8Decoder.decode(bytes);
126
- return JSON.parse(decoded);
127
- } catch (e) {
128
- throw new SDJWTException(errorMessage);
129
- }
63
+ //#endregion
64
+ //#region src/utils/strict-json.ts
65
+ /**
66
+ * Decode base64url encoded JSON with {@link base64urlDecodeJson}, rethrowing failures as an
67
+ * `SDJWTException` with the given message.
68
+ */
69
+ const decodeBase64urlJsonStrict = (encoded, errorMessage) => {
70
+ try {
71
+ return base64urlDecodeJson(encoded);
72
+ } catch {
73
+ throw new SDJWTException(errorMessage);
74
+ }
130
75
  };
131
-
132
- // src/utils/disclosure.ts
133
- var Disclosure = class _Disclosure {
134
- constructor(data, _meta) {
135
- if (!Array.isArray(data) || data.length !== 2 && data.length !== 3) {
136
- throw new SDJWTException("Invalid disclosure data");
137
- }
138
- if (typeof data[0] !== "string") {
139
- throw new SDJWTException("Invalid disclosure salt");
140
- }
141
- this._digest = _meta == null ? void 0 : _meta.digest;
142
- this._encoded = _meta == null ? void 0 : _meta.encoded;
143
- if (data.length === 2) {
144
- this.salt = data[0];
145
- this.value = data[1];
146
- return;
147
- }
148
- if (data.length === 3) {
149
- if (typeof data[1] !== "string") {
150
- throw new SDJWTException("Invalid disclosure claim name");
151
- }
152
- if (data[1] === SD_DIGEST || data[1] === SD_LIST_KEY) {
153
- throw new SDJWTException(
154
- `Reserved disclosure claim name "${data[1]}" is not allowed`
155
- );
156
- }
157
- this.salt = data[0];
158
- this.key = data[1];
159
- this.value = data[2];
160
- return;
161
- }
162
- }
163
- // We need to digest of the original encoded data.
164
- // After decode process, we use JSON.stringify to encode the data.
165
- // This can be different from the original encoded data.
166
- static fromEncode(s, hash) {
167
- return __async(this, null, function* () {
168
- const { hasher, alg } = hash;
169
- const digest = yield hasher(s, alg);
170
- const digestStr = uint8ArrayToBase64Url(digest);
171
- const item = decodeBase64urlJsonStrict(
172
- s,
173
- "Invalid disclosure data"
174
- );
175
- return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
176
- });
177
- }
178
- static fromEncodeSync(s, hash) {
179
- const { hasher, alg } = hash;
180
- const digest = hasher(s, alg);
181
- const digestStr = uint8ArrayToBase64Url(digest);
182
- const item = decodeBase64urlJsonStrict(
183
- s,
184
- "Invalid disclosure data"
185
- );
186
- return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
187
- }
188
- static fromArray(item, _meta) {
189
- return new _Disclosure(item, _meta);
190
- }
191
- encode() {
192
- if (!this._encoded) {
193
- this._encoded = base64urlEncode(JSON.stringify(this.decode()));
194
- }
195
- return this._encoded;
196
- }
197
- decode() {
198
- return this.key ? [this.salt, this.key, this.value] : [this.salt, this.value];
199
- }
200
- digest(hash) {
201
- return __async(this, null, function* () {
202
- const { hasher, alg } = hash;
203
- if (!this._digest) {
204
- const hash2 = yield hasher(this.encode(), alg);
205
- this._digest = uint8ArrayToBase64Url(hash2);
206
- }
207
- return this._digest;
208
- });
209
- }
210
- digestSync(hash) {
211
- const { hasher, alg } = hash;
212
- if (!this._digest) {
213
- const hash2 = hasher(this.encode(), alg);
214
- this._digest = uint8ArrayToBase64Url(hash2);
215
- }
216
- return this._digest;
217
- }
76
+ //#endregion
77
+ //#region src/utils/disclosure.ts
78
+ var Disclosure = class Disclosure {
79
+ constructor(data, _meta) {
80
+ if (!Array.isArray(data) || data.length !== 2 && data.length !== 3) throw new SDJWTException("Invalid disclosure data");
81
+ if (typeof data[0] !== "string") throw new SDJWTException("Invalid disclosure salt");
82
+ this._digest = _meta?.digest;
83
+ this._encoded = _meta?.encoded;
84
+ if (data.length === 2) {
85
+ this.salt = data[0];
86
+ this.value = data[1];
87
+ return;
88
+ }
89
+ if (data.length === 3) {
90
+ if (typeof data[1] !== "string") throw new SDJWTException("Invalid disclosure claim name");
91
+ if (data[1] === "_sd" || data[1] === "...") throw new SDJWTException(`Reserved disclosure claim name "${data[1]}" is not allowed`);
92
+ this.salt = data[0];
93
+ this.key = data[1];
94
+ this.value = data[2];
95
+ return;
96
+ }
97
+ }
98
+ static async fromEncode(s, hash) {
99
+ const { hasher, alg } = hash;
100
+ const digest = await hasher(s, alg);
101
+ const digestStr = uint8ArrayToBase64Url(digest);
102
+ const item = decodeBase64urlJsonStrict(s, "Invalid disclosure data");
103
+ return Disclosure.fromArray(item, {
104
+ digest: digestStr,
105
+ encoded: s
106
+ });
107
+ }
108
+ static fromEncodeSync(s, hash) {
109
+ const { hasher, alg } = hash;
110
+ const digest = hasher(s, alg);
111
+ const digestStr = uint8ArrayToBase64Url(digest);
112
+ const item = decodeBase64urlJsonStrict(s, "Invalid disclosure data");
113
+ return Disclosure.fromArray(item, {
114
+ digest: digestStr,
115
+ encoded: s
116
+ });
117
+ }
118
+ static fromArray(item, _meta) {
119
+ return new Disclosure(item, _meta);
120
+ }
121
+ encode() {
122
+ if (!this._encoded) this._encoded = base64urlEncode(JSON.stringify(this.decode()));
123
+ return this._encoded;
124
+ }
125
+ decode() {
126
+ return this.key ? [
127
+ this.salt,
128
+ this.key,
129
+ this.value
130
+ ] : [this.salt, this.value];
131
+ }
132
+ async digest(hash) {
133
+ const { hasher, alg } = hash;
134
+ if (!this._digest) {
135
+ const hash = await hasher(this.encode(), alg);
136
+ this._digest = uint8ArrayToBase64Url(hash);
137
+ }
138
+ return this._digest;
139
+ }
140
+ digestSync(hash) {
141
+ const { hasher, alg } = hash;
142
+ if (!this._digest) {
143
+ const hash = hasher(this.encode(), alg);
144
+ this._digest = uint8ArrayToBase64Url(hash);
145
+ }
146
+ return this._digest;
147
+ }
218
148
  };
219
-
220
- // src/decode/decode.ts
221
- var decodeJwt = (jwt) => {
222
- const { 0: header, 1: payload, 2: signature, length } = jwt.split(".");
223
- if (length !== 3) {
224
- throw new SDJWTException("Invalid JWT as input");
225
- }
226
- return {
227
- header: decodeBase64urlJsonStrict(header, "Invalid JWT as input"),
228
- payload: decodeBase64urlJsonStrict(payload, "Invalid JWT as input"),
229
- signature
230
- };
149
+ //#endregion
150
+ //#region src/decode/decode.ts
151
+ /**
152
+ * Decode a JWT with `decodeJwt` from `@owf/identity-common`, rethrowing failures as an `SDJWTException`.
153
+ */
154
+ const decodeJwt = (jwt) => {
155
+ try {
156
+ return decodeJwt$1(jwt);
157
+ } catch {
158
+ throw new SDJWTException("Invalid JWT as input");
159
+ }
231
160
  };
232
- var splitSdJwt = (sdjwt) => {
233
- const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
234
- if (encodedDisclosures.length === 0) {
235
- throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
236
- }
237
- const encodedKeyBindingJwt = encodedDisclosures.pop();
238
- return {
239
- jwt: encodedJwt,
240
- disclosures: encodedDisclosures,
241
- kbJwt: encodedKeyBindingJwt || void 0
242
- };
161
+ const splitSdJwt = (sdjwt) => {
162
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
163
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
164
+ return {
165
+ jwt: encodedJwt,
166
+ disclosures: encodedDisclosures,
167
+ kbJwt: encodedDisclosures.pop() || void 0
168
+ };
243
169
  };
244
- var decodeSdJwt = (sdjwt, hasher) => __async(null, null, function* () {
245
- const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
246
- const jwt = decodeJwt(encodedJwt);
247
- if (encodedDisclosures.length === 0) {
248
- throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
249
- }
250
- const encodedKeyBindingJwt = encodedDisclosures.pop();
251
- const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
252
- const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
253
- const disclosures = yield Promise.all(
254
- encodedDisclosures.map(
255
- (ed) => Disclosure.fromEncode(ed, { alg: _sd_alg, hasher })
256
- )
257
- );
258
- return {
259
- jwt,
260
- disclosures,
261
- kbJwt
262
- };
263
- });
264
- var decodeSdJwtSync = (sdjwt, hasher) => {
265
- const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
266
- const jwt = decodeJwt(encodedJwt);
267
- if (encodedDisclosures.length === 0) {
268
- throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
269
- }
270
- const encodedKeyBindingJwt = encodedDisclosures.pop();
271
- const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
272
- const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
273
- const disclosures = encodedDisclosures.map(
274
- (ed) => Disclosure.fromEncodeSync(ed, { alg: _sd_alg, hasher })
275
- );
276
- return {
277
- jwt,
278
- disclosures,
279
- kbJwt
280
- };
170
+ const decodeSdJwt = async (sdjwt, hasher) => {
171
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
172
+ const jwt = decodeJwt(encodedJwt);
173
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
174
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
175
+ const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
176
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
177
+ return {
178
+ jwt,
179
+ disclosures: await Promise.all(encodedDisclosures.map((ed) => Disclosure.fromEncode(ed, {
180
+ alg: _sd_alg,
181
+ hasher
182
+ }))),
183
+ kbJwt
184
+ };
281
185
  };
282
- var getClaims = (rawPayload, disclosures, hasher) => __async(null, null, function* () {
283
- const { unpackedObj } = yield unpack(rawPayload, disclosures, hasher);
284
- return unpackedObj;
285
- });
286
- var getClaimsSync = (rawPayload, disclosures, hasher) => {
287
- const { unpackedObj } = unpackSync(rawPayload, disclosures, hasher);
288
- return unpackedObj;
186
+ const decodeSdJwtSync = (sdjwt, hasher) => {
187
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
188
+ const jwt = decodeJwt(encodedJwt);
189
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
190
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
191
+ const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
192
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
193
+ return {
194
+ jwt,
195
+ disclosures: encodedDisclosures.map((ed) => Disclosure.fromEncodeSync(ed, {
196
+ alg: _sd_alg,
197
+ hasher
198
+ })),
199
+ kbJwt
200
+ };
289
201
  };
290
- var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
291
- var unpackArray = (arr, map, prefix = "", seenDigests) => {
292
- const keys = {};
293
- const unpackedArray = [];
294
- arr.forEach((item, idx) => {
295
- if (isRecord(item)) {
296
- const hash = item[SD_LIST_KEY];
297
- if (SD_LIST_KEY in item) {
298
- if (Object.keys(item).length !== 1 || typeof hash !== "string") {
299
- throw new SDJWTException("Invalid array disclosure placeholder");
300
- }
301
- if (seenDigests) {
302
- if (seenDigests.has(hash)) {
303
- throw new SDJWTException(
304
- "Duplicate digest found in SD-JWT payload"
305
- );
306
- }
307
- seenDigests.add(hash);
308
- }
309
- const disclosed = map[hash];
310
- if (disclosed) {
311
- if (typeof disclosed.key === "string") {
312
- throw new SDJWTException(
313
- "Object-property disclosure cannot be used as an array element"
314
- );
315
- }
316
- const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
317
- keys[presentKey] = hash;
318
- const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
319
- unpackedArray.push(unpackedObj);
320
- Object.assign(keys, disclosureKeys);
321
- }
322
- } else {
323
- const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
324
- const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
325
- unpackedArray.push(unpackedObj);
326
- Object.assign(keys, disclosureKeys);
327
- }
328
- } else if (Array.isArray(item)) {
329
- const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
330
- const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
331
- unpackedArray.push(unpackedObj);
332
- Object.assign(keys, disclosureKeys);
333
- } else {
334
- unpackedArray.push(item);
335
- }
336
- });
337
- return { unpackedObj: unpackedArray, disclosureKeymap: keys };
202
+ const getClaims = async (rawPayload, disclosures, hasher) => {
203
+ const { unpackedObj } = await unpack(rawPayload, disclosures, hasher);
204
+ return unpackedObj;
338
205
  };
339
- var unpackObj = (obj, map) => {
340
- const copiedObj = JSON.parse(JSON.stringify(obj));
341
- const seenDigests = /* @__PURE__ */ new Set();
342
- const result = unpackObjInternal(copiedObj, map, "", seenDigests);
343
- const mapDigests = Object.keys(map);
344
- const unusedDigests = mapDigests.filter((d) => !seenDigests.has(d));
345
- if (unusedDigests.length > 0) {
346
- throw new SDJWTException("Unreferenced disclosure(s) detected in SD-JWT");
347
- }
348
- return result;
206
+ const getClaimsSync = (rawPayload, disclosures, hasher) => {
207
+ const { unpackedObj } = unpackSync(rawPayload, disclosures, hasher);
208
+ return unpackedObj;
349
209
  };
350
- var unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
351
- const keys = {};
352
- if (typeof obj === "object" && obj !== null) {
353
- if (Array.isArray(obj)) {
354
- return unpackArray(obj, map, prefix, seenDigests);
355
- }
356
- const record = obj;
357
- for (const key in record) {
358
- if (prefix && key === "_sd_alg") {
359
- throw new SDJWTException("Nested _sd_alg is not allowed");
360
- }
361
- if (key !== SD_DIGEST && key !== SD_LIST_KEY && typeof record[key] === "object") {
362
- const escapedKey = encodePathSegment(key);
363
- const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
364
- const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(record[key], map, newKey, seenDigests);
365
- record[key] = unpackedObj2;
366
- Object.assign(keys, disclosureKeys);
367
- }
368
- }
369
- const _a = record, { _sd } = _a, payload = __objRest(_a, ["_sd"]);
370
- const claims = {};
371
- if (_sd !== void 0) {
372
- if (!Array.isArray(_sd) || !_sd.every((hash) => typeof hash === "string")) {
373
- throw new SDJWTException(
374
- "Invalid _sd claim: expected array of strings"
375
- );
376
- }
377
- for (const hash of _sd) {
378
- if (seenDigests) {
379
- if (seenDigests.has(hash)) {
380
- throw new SDJWTException(
381
- "Duplicate digest found in SD-JWT payload"
382
- );
383
- }
384
- seenDigests.add(hash);
385
- }
386
- const disclosed = map[hash];
387
- if (disclosed) {
388
- if (typeof disclosed.key !== "string") {
389
- throw new SDJWTException(
390
- "Array disclosure cannot be used as an object property"
391
- );
392
- }
393
- if (disclosed.key in payload) {
394
- throw new SDJWTException(
395
- `Disclosed claim name "${disclosed.key}" conflicts with existing payload key`
396
- );
397
- }
398
- if (disclosed.key in claims) {
399
- throw new SDJWTException(
400
- `Disclosed claim name "${disclosed.key}" conflicts with another disclosure`
401
- );
402
- }
403
- const escapedKey = encodePathSegment(disclosed.key);
404
- const presentKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
405
- keys[presentKey] = hash;
406
- const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
407
- claims[disclosed.key] = unpackedObj2;
408
- Object.assign(keys, disclosureKeys);
409
- }
410
- }
411
- }
412
- const unpackedObj = Object.assign(payload, claims);
413
- return { unpackedObj, disclosureKeymap: keys };
414
- }
415
- return { unpackedObj: obj, disclosureKeymap: keys };
210
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
211
+ const unpackArray = (arr, map, prefix = "", seenDigests) => {
212
+ const keys = {};
213
+ const unpackedArray = [];
214
+ arr.forEach((item, idx) => {
215
+ if (isRecord(item)) {
216
+ const hash = item["..."];
217
+ if ("..." in item) {
218
+ if (Object.keys(item).length !== 1 || typeof hash !== "string") throw new SDJWTException("Invalid array disclosure placeholder");
219
+ if (seenDigests) {
220
+ if (seenDigests.has(hash)) throw new SDJWTException("Duplicate digest found in SD-JWT payload");
221
+ seenDigests.add(hash);
222
+ }
223
+ const disclosed = map[hash];
224
+ if (disclosed) {
225
+ if (typeof disclosed.key === "string") throw new SDJWTException("Object-property disclosure cannot be used as an array element");
226
+ const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
227
+ keys[presentKey] = hash;
228
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
229
+ unpackedArray.push(unpackedObj);
230
+ Object.assign(keys, disclosureKeys);
231
+ }
232
+ } else {
233
+ const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
234
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
235
+ unpackedArray.push(unpackedObj);
236
+ Object.assign(keys, disclosureKeys);
237
+ }
238
+ } else if (Array.isArray(item)) {
239
+ const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
240
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
241
+ unpackedArray.push(unpackedObj);
242
+ Object.assign(keys, disclosureKeys);
243
+ } else unpackedArray.push(item);
244
+ });
245
+ return {
246
+ unpackedObj: unpackedArray,
247
+ disclosureKeymap: keys
248
+ };
416
249
  };
417
- var createHashMapping = (disclosures, hash) => __async(null, null, function* () {
418
- const map = {};
419
- for (let i = 0; i < disclosures.length; i++) {
420
- const disclosure = disclosures[i];
421
- const digest = yield disclosure.digest(hash);
422
- if (digest in map) {
423
- throw new SDJWTException("Duplicate disclosure digest detected");
424
- }
425
- map[digest] = disclosure;
426
- }
427
- return map;
428
- });
429
- var createHashMappingSync = (disclosures, hash) => {
430
- const map = {};
431
- for (let i = 0; i < disclosures.length; i++) {
432
- const disclosure = disclosures[i];
433
- const digest = disclosure.digestSync(hash);
434
- if (digest in map) {
435
- throw new SDJWTException("Duplicate disclosure digest detected");
436
- }
437
- map[digest] = disclosure;
438
- }
439
- return map;
250
+ const unpackObj = (obj, map) => {
251
+ const copiedObj = JSON.parse(JSON.stringify(obj));
252
+ const seenDigests = /* @__PURE__ */ new Set();
253
+ const result = unpackObjInternal(copiedObj, map, "", seenDigests);
254
+ if (Object.keys(map).filter((d) => !seenDigests.has(d)).length > 0) throw new SDJWTException("Unreferenced disclosure(s) detected in SD-JWT");
255
+ return result;
440
256
  };
441
- var getSDAlgAndPayload = (SdJwtPayload, allowedAlgorithms = DEFAULT_SECURE_HASH_ALGORITHMS) => {
442
- const _a = SdJwtPayload, { _sd_alg } = _a, payload = __objRest(_a, ["_sd_alg"]);
443
- if (_sd_alg === void 0) {
444
- return { _sd_alg: "sha-256", payload };
445
- }
446
- if (typeof _sd_alg !== "string") {
447
- throw new SDJWTException("Invalid _sd_alg: expected string");
448
- }
449
- if (!IANA_HASH_ALGORITHMS.includes(
450
- _sd_alg
451
- )) {
452
- throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
453
- }
454
- if (!allowedAlgorithms.includes(_sd_alg)) {
455
- throw new SDJWTException(`Disallowed _sd_alg: ${_sd_alg}`);
456
- }
457
- return { _sd_alg, payload };
257
+ const unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
258
+ const keys = {};
259
+ if (typeof obj === "object" && obj !== null) {
260
+ if (Array.isArray(obj)) return unpackArray(obj, map, prefix, seenDigests);
261
+ const record = obj;
262
+ for (const key in record) {
263
+ if (prefix && key === "_sd_alg") throw new SDJWTException("Nested _sd_alg is not allowed");
264
+ if (key !== "_sd" && key !== "..." && typeof record[key] === "object") {
265
+ const escapedKey = encodePathSegment(key);
266
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
267
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(record[key], map, newKey, seenDigests);
268
+ record[key] = unpackedObj;
269
+ Object.assign(keys, disclosureKeys);
270
+ }
271
+ }
272
+ const { _sd, ...payload } = record;
273
+ const claims = {};
274
+ if (_sd !== void 0) {
275
+ if (!Array.isArray(_sd) || !_sd.every((hash) => typeof hash === "string")) throw new SDJWTException("Invalid _sd claim: expected array of strings");
276
+ for (const hash of _sd) {
277
+ if (seenDigests) {
278
+ if (seenDigests.has(hash)) throw new SDJWTException("Duplicate digest found in SD-JWT payload");
279
+ seenDigests.add(hash);
280
+ }
281
+ const disclosed = map[hash];
282
+ if (disclosed) {
283
+ if (typeof disclosed.key !== "string") throw new SDJWTException("Array disclosure cannot be used as an object property");
284
+ if (disclosed.key in payload) throw new SDJWTException(`Disclosed claim name "${disclosed.key}" conflicts with existing payload key`);
285
+ if (disclosed.key in claims) throw new SDJWTException(`Disclosed claim name "${disclosed.key}" conflicts with another disclosure`);
286
+ const escapedKey = encodePathSegment(disclosed.key);
287
+ const presentKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
288
+ keys[presentKey] = hash;
289
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
290
+ claims[disclosed.key] = unpackedObj;
291
+ Object.assign(keys, disclosureKeys);
292
+ }
293
+ }
294
+ }
295
+ return {
296
+ unpackedObj: Object.assign(payload, claims),
297
+ disclosureKeymap: keys
298
+ };
299
+ }
300
+ return {
301
+ unpackedObj: obj,
302
+ disclosureKeymap: keys
303
+ };
458
304
  };
459
- var unpack = (SdJwtPayload, disclosures, hasher) => __async(null, null, function* () {
460
- const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
461
- const hash = { hasher, alg: _sd_alg };
462
- const map = yield createHashMapping(disclosures, hash);
463
- return unpackObj(payload, map);
464
- });
465
- var unpackSync = (SdJwtPayload, disclosures, hasher) => {
466
- const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
467
- const hash = { hasher, alg: _sd_alg };
468
- const map = createHashMappingSync(disclosures, hash);
469
- return unpackObj(payload, map);
305
+ const createHashMapping = async (disclosures, hash) => {
306
+ const map = {};
307
+ for (let i = 0; i < disclosures.length; i++) {
308
+ const disclosure = disclosures[i];
309
+ const digest = await disclosure.digest(hash);
310
+ if (digest in map) throw new SDJWTException("Duplicate disclosure digest detected");
311
+ map[digest] = disclosure;
312
+ }
313
+ return map;
470
314
  };
471
-
472
- // src/flattenJSON.ts
473
- var FlattenJSON = class _FlattenJSON {
474
- constructor(data) {
475
- this.disclosures = data.disclosures;
476
- this.kb_jwt = data.kb_jwt;
477
- this.payload = data.jwtData.payload;
478
- this.signature = data.jwtData.signature;
479
- this.protected = data.jwtData.protected;
480
- }
481
- static fromEncode(encodedSdJwt) {
482
- const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
483
- const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
484
- if (!protectedHeader || !payload || !signature) {
485
- throw new SDJWTException("Invalid JWT");
486
- }
487
- return new _FlattenJSON({
488
- jwtData: {
489
- protected: protectedHeader,
490
- payload,
491
- signature
492
- },
493
- disclosures,
494
- kb_jwt: kbJwt
495
- });
496
- }
497
- static fromSerialized(json) {
498
- return new _FlattenJSON({
499
- jwtData: {
500
- protected: json.protected,
501
- payload: json.payload,
502
- signature: json.signature
503
- },
504
- disclosures: json.header.disclosures,
505
- kb_jwt: json.header.kb_jwt
506
- });
507
- }
508
- toJson() {
509
- return {
510
- payload: this.payload,
511
- signature: this.signature,
512
- protected: this.protected,
513
- header: {
514
- disclosures: this.disclosures,
515
- kb_jwt: this.kb_jwt
516
- }
517
- };
518
- }
519
- toEncoded() {
520
- var _a;
521
- const data = [];
522
- const jwt = `${this.protected}.${this.payload}.${this.signature}`;
523
- data.push(jwt);
524
- if (this.disclosures && this.disclosures.length > 0) {
525
- const disclosures = this.disclosures.join(SD_SEPARATOR);
526
- data.push(disclosures);
527
- }
528
- const kb_jwt = (_a = this.kb_jwt) != null ? _a : "";
529
- data.push(kb_jwt);
530
- return data.join(SD_SEPARATOR);
531
- }
315
+ const createHashMappingSync = (disclosures, hash) => {
316
+ const map = {};
317
+ for (let i = 0; i < disclosures.length; i++) {
318
+ const disclosure = disclosures[i];
319
+ const digest = disclosure.digestSync(hash);
320
+ if (digest in map) throw new SDJWTException("Duplicate disclosure digest detected");
321
+ map[digest] = disclosure;
322
+ }
323
+ return map;
532
324
  };
533
-
534
- // src/generalJSON.ts
535
- var GeneralJSON = class _GeneralJSON {
536
- constructor(data) {
537
- this.payload = data.payload;
538
- this.disclosures = data.disclosures;
539
- this.kb_jwt = data.kb_jwt;
540
- this.signatures = data.signatures;
541
- }
542
- static fromEncode(encodedSdJwt) {
543
- const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
544
- const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
545
- if (!protectedHeader || !payload || !signature) {
546
- throw new SDJWTException("Invalid JWT");
547
- }
548
- return new _GeneralJSON({
549
- payload,
550
- disclosures,
551
- kb_jwt: kbJwt,
552
- signatures: [
553
- {
554
- protected: protectedHeader,
555
- signature
556
- }
557
- ]
558
- });
559
- }
560
- static fromSerialized(json) {
561
- var _a, _b, _c;
562
- if (!json.signatures[0]) {
563
- throw new SDJWTException("Invalid JSON");
564
- }
565
- for (let index = 1; index < json.signatures.length; index++) {
566
- const header = json.signatures[index].header;
567
- if (header && ("disclosures" in header || "kb_jwt" in header)) {
568
- throw new SDJWTException(
569
- "disclosures and kb_jwt MUST only appear in the first unprotected header"
570
- );
571
- }
572
- }
573
- const disclosures = (_b = (_a = json.signatures[0].header) == null ? void 0 : _a.disclosures) != null ? _b : [];
574
- const kb_jwt = (_c = json.signatures[0].header) == null ? void 0 : _c.kb_jwt;
575
- return new _GeneralJSON({
576
- payload: json.payload,
577
- disclosures,
578
- kb_jwt,
579
- signatures: json.signatures.map((s) => {
580
- var _a2;
581
- return {
582
- protected: s.protected,
583
- signature: s.signature,
584
- kid: (_a2 = s.header) == null ? void 0 : _a2.kid
585
- };
586
- })
587
- });
588
- }
589
- toJson() {
590
- return {
591
- payload: this.payload,
592
- signatures: this.signatures.map((s, i) => {
593
- if (i !== 0) {
594
- return {
595
- header: {
596
- kid: s.kid
597
- },
598
- protected: s.protected,
599
- signature: s.signature
600
- };
601
- }
602
- return {
603
- header: {
604
- disclosures: this.disclosures,
605
- kid: s.kid,
606
- kb_jwt: this.kb_jwt
607
- },
608
- protected: s.protected,
609
- signature: s.signature
610
- };
611
- })
612
- };
613
- }
614
- toEncoded(index) {
615
- var _a;
616
- if (index < 0 || index >= this.signatures.length) {
617
- throw new SDJWTException("Index out of bounds");
618
- }
619
- const data = [];
620
- const { protected: protectedHeader, signature } = this.signatures[index];
621
- const jwt = `${protectedHeader}.${this.payload}.${signature}`;
622
- data.push(jwt);
623
- if (this.disclosures && this.disclosures.length > 0) {
624
- const disclosures = this.disclosures.join(SD_SEPARATOR);
625
- data.push(disclosures);
626
- }
627
- const kb = (_a = this.kb_jwt) != null ? _a : "";
628
- data.push(kb);
629
- return data.join(SD_SEPARATOR);
630
- }
631
- addSignature(protectedHeader, signer, kid) {
632
- return __async(this, null, function* () {
633
- const header = base64urlEncode(JSON.stringify(protectedHeader));
634
- const signature = yield signer(`${header}.${this.payload}`);
635
- this.signatures.push({
636
- protected: header,
637
- signature,
638
- kid
639
- });
640
- });
641
- }
325
+ const getSDAlgAndPayload = (SdJwtPayload, allowedAlgorithms = DEFAULT_SECURE_HASH_ALGORITHMS) => {
326
+ const { _sd_alg, ...payload } = SdJwtPayload;
327
+ if (_sd_alg === void 0) return {
328
+ _sd_alg: "sha-256",
329
+ payload
330
+ };
331
+ if (typeof _sd_alg !== "string") throw new SDJWTException("Invalid _sd_alg: expected string");
332
+ if (!IANA_HASH_ALGORITHMS.includes(_sd_alg)) throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
333
+ if (!allowedAlgorithms.includes(_sd_alg)) throw new SDJWTException(`Disallowed _sd_alg: ${_sd_alg}`);
334
+ return {
335
+ _sd_alg,
336
+ payload
337
+ };
642
338
  };
643
-
644
- // src/jwt.ts
645
- var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
646
- var validateNumericDate = (payload, claim) => {
647
- const value = payload[claim];
648
- if (value === void 0) return void 0;
649
- if (typeof value !== "number" || !Number.isFinite(value)) {
650
- throw new SDJWTException(`Verify Error: JWT ${claim} must be a number`);
651
- }
652
- return value;
339
+ const unpack = async (SdJwtPayload, disclosures, hasher) => {
340
+ const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
341
+ const map = await createHashMapping(disclosures, {
342
+ hasher,
343
+ alg: _sd_alg
344
+ });
345
+ return unpackObj(payload, map);
653
346
  };
654
- var getAudiences = (audience) => {
655
- if (typeof audience === "string") return [audience];
656
- if (isStringArray(audience)) return audience;
657
- return void 0;
347
+ const unpackSync = (SdJwtPayload, disclosures, hasher) => {
348
+ const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
349
+ const map = createHashMappingSync(disclosures, {
350
+ hasher,
351
+ alg: _sd_alg
352
+ });
353
+ return unpackObj(payload, map);
658
354
  };
659
- var validateAudience = (payload, expectedAudience) => {
660
- if (expectedAudience === void 0) return;
661
- const expectedAudiences = Array.isArray(expectedAudience) ? expectedAudience : [expectedAudience];
662
- const audiences = getAudiences(payload.aud);
663
- if (!audiences || !expectedAudiences.some((expected) => audiences.includes(expected))) {
664
- throw new SDJWTException("Verify Error: Invalid audience");
665
- }
355
+ //#endregion
356
+ //#region src/flattenJSON.ts
357
+ var FlattenJSON = class FlattenJSON {
358
+ constructor(data) {
359
+ this.disclosures = data.disclosures;
360
+ this.kb_jwt = data.kb_jwt;
361
+ this.payload = data.jwtData.payload;
362
+ this.signature = data.jwtData.signature;
363
+ this.protected = data.jwtData.protected;
364
+ }
365
+ static fromEncode(encodedSdJwt) {
366
+ const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
367
+ const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
368
+ if (!protectedHeader || !payload || !signature) throw new SDJWTException("Invalid JWT");
369
+ return new FlattenJSON({
370
+ jwtData: {
371
+ protected: protectedHeader,
372
+ payload,
373
+ signature
374
+ },
375
+ disclosures,
376
+ kb_jwt: kbJwt
377
+ });
378
+ }
379
+ static fromSerialized(json) {
380
+ return new FlattenJSON({
381
+ jwtData: {
382
+ protected: json.protected,
383
+ payload: json.payload,
384
+ signature: json.signature
385
+ },
386
+ disclosures: json.header.disclosures,
387
+ kb_jwt: json.header.kb_jwt
388
+ });
389
+ }
390
+ toJson() {
391
+ return {
392
+ payload: this.payload,
393
+ signature: this.signature,
394
+ protected: this.protected,
395
+ header: {
396
+ disclosures: this.disclosures,
397
+ kb_jwt: this.kb_jwt
398
+ }
399
+ };
400
+ }
401
+ toEncoded() {
402
+ const data = [];
403
+ const jwt = `${this.protected}.${this.payload}.${this.signature}`;
404
+ data.push(jwt);
405
+ if (this.disclosures && this.disclosures.length > 0) {
406
+ const disclosures = this.disclosures.join("~");
407
+ data.push(disclosures);
408
+ }
409
+ const kb_jwt = this.kb_jwt ?? "";
410
+ data.push(kb_jwt);
411
+ return data.join("~");
412
+ }
666
413
  };
667
- var validateJwtPayload = (payload, options) => {
668
- var _a;
669
- if (!payload) {
670
- throw new SDJWTException("Verify Error: JWT payload is missing");
671
- }
672
- const skew = (options == null ? void 0 : options.skewSeconds) ? options.skewSeconds : 0;
673
- const currentDate = (_a = options == null ? void 0 : options.currentDate) != null ? _a : Math.floor(Date.now() / 1e3);
674
- const iat = validateNumericDate(payload, "iat");
675
- const nbf = validateNumericDate(payload, "nbf");
676
- const exp = validateNumericDate(payload, "exp");
677
- if (iat !== void 0 && iat - skew > currentDate) {
678
- throw new SDJWTException("Verify Error: JWT is not yet valid");
679
- }
680
- if (nbf !== void 0 && nbf - skew > currentDate) {
681
- throw new SDJWTException("Verify Error: JWT is not yet valid");
682
- }
683
- if (exp !== void 0 && exp + skew <= currentDate) {
684
- throw new SDJWTException("Verify Error: JWT is expired");
685
- }
686
- validateAudience(payload, options == null ? void 0 : options.expectedAudience);
414
+ //#endregion
415
+ //#region src/generalJSON.ts
416
+ var GeneralJSON = class GeneralJSON {
417
+ constructor(data) {
418
+ this.payload = data.payload;
419
+ this.disclosures = data.disclosures;
420
+ this.kb_jwt = data.kb_jwt;
421
+ this.signatures = data.signatures;
422
+ }
423
+ static fromEncode(encodedSdJwt) {
424
+ const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
425
+ const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
426
+ if (!protectedHeader || !payload || !signature) throw new SDJWTException("Invalid JWT");
427
+ return new GeneralJSON({
428
+ payload,
429
+ disclosures,
430
+ kb_jwt: kbJwt,
431
+ signatures: [{
432
+ protected: protectedHeader,
433
+ signature
434
+ }]
435
+ });
436
+ }
437
+ static fromSerialized(json) {
438
+ if (!json.signatures[0]) throw new SDJWTException("Invalid JSON");
439
+ for (let index = 1; index < json.signatures.length; index++) {
440
+ const header = json.signatures[index].header;
441
+ if (header && ("disclosures" in header || "kb_jwt" in header)) throw new SDJWTException("disclosures and kb_jwt MUST only appear in the first unprotected header");
442
+ }
443
+ const disclosures = json.signatures[0].header?.disclosures ?? [];
444
+ const kb_jwt = json.signatures[0].header?.kb_jwt;
445
+ return new GeneralJSON({
446
+ payload: json.payload,
447
+ disclosures,
448
+ kb_jwt,
449
+ signatures: json.signatures.map((s) => {
450
+ return {
451
+ protected: s.protected,
452
+ signature: s.signature,
453
+ kid: s.header?.kid
454
+ };
455
+ })
456
+ });
457
+ }
458
+ toJson() {
459
+ return {
460
+ payload: this.payload,
461
+ signatures: this.signatures.map((s, i) => {
462
+ if (i !== 0) return {
463
+ header: { kid: s.kid },
464
+ protected: s.protected,
465
+ signature: s.signature
466
+ };
467
+ return {
468
+ header: {
469
+ disclosures: this.disclosures,
470
+ kid: s.kid,
471
+ kb_jwt: this.kb_jwt
472
+ },
473
+ protected: s.protected,
474
+ signature: s.signature
475
+ };
476
+ })
477
+ };
478
+ }
479
+ toEncoded(index) {
480
+ if (index < 0 || index >= this.signatures.length) throw new SDJWTException("Index out of bounds");
481
+ const data = [];
482
+ const { protected: protectedHeader, signature } = this.signatures[index];
483
+ const jwt = `${protectedHeader}.${this.payload}.${signature}`;
484
+ data.push(jwt);
485
+ if (this.disclosures && this.disclosures.length > 0) {
486
+ const disclosures = this.disclosures.join("~");
487
+ data.push(disclosures);
488
+ }
489
+ const kb = this.kb_jwt ?? "";
490
+ data.push(kb);
491
+ return data.join("~");
492
+ }
493
+ async addSignature(protectedHeader, signer, kid) {
494
+ const header = base64urlEncode(JSON.stringify(protectedHeader));
495
+ const signature = await signer(`${header}.${this.payload}`);
496
+ this.signatures.push({
497
+ protected: header,
498
+ signature,
499
+ kid
500
+ });
501
+ }
687
502
  };
688
- var Jwt = class _Jwt {
689
- constructor(data) {
690
- this.header = data == null ? void 0 : data.header;
691
- this.payload = data == null ? void 0 : data.payload;
692
- this.signature = data == null ? void 0 : data.signature;
693
- this.encoded = data == null ? void 0 : data.encoded;
694
- }
695
- static decodeJWT(jwt) {
696
- return decodeJwt(jwt);
697
- }
698
- static fromEncode(encodedJwt) {
699
- const { header, payload, signature } = _Jwt.decodeJWT(
700
- encodedJwt
701
- );
702
- const jwt = new _Jwt({
703
- header,
704
- payload,
705
- signature,
706
- encoded: encodedJwt
707
- });
708
- return jwt;
709
- }
710
- setHeader(header) {
711
- this.header = header;
712
- this.encoded = void 0;
713
- return this;
714
- }
715
- setPayload(payload) {
716
- this.payload = payload;
717
- this.encoded = void 0;
718
- return this;
719
- }
720
- getUnsignedToken() {
721
- if (!this.header || !this.payload) {
722
- throw new SDJWTException("Serialize Error: Invalid JWT");
723
- }
724
- if (this.encoded) {
725
- const parts = this.encoded.split(".");
726
- if (parts.length !== 3) {
727
- throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
728
- }
729
- const unsignedToken = parts.slice(0, 2).join(".");
730
- return unsignedToken;
731
- }
732
- const header = base64urlEncode(JSON.stringify(this.header));
733
- const payload = base64urlEncode(JSON.stringify(this.payload));
734
- return `${header}.${payload}`;
735
- }
736
- sign(signer) {
737
- return __async(this, null, function* () {
738
- if (!this.header || this.header.alg === "none") {
739
- throw new SDJWTException('Sign Error: alg "none" is not allowed');
740
- }
741
- const data = this.getUnsignedToken();
742
- this.signature = yield signer(data);
743
- return this.encodeJwt();
744
- });
745
- }
746
- encodeJwt() {
747
- if (this.encoded) {
748
- return this.encoded;
749
- }
750
- if (!this.header || !this.payload || !this.signature) {
751
- throw new SDJWTException("Serialize Error: Invalid JWT");
752
- }
753
- const header = base64urlEncode(JSON.stringify(this.header));
754
- const payload = base64urlEncode(JSON.stringify(this.payload));
755
- const signature = this.signature;
756
- const compact = `${header}.${payload}.${signature}`;
757
- this.encoded = compact;
758
- return compact;
759
- }
760
- /**
761
- * Verify the JWT using the provided verifier function.
762
- * It checks the signature and validates the iat, nbf, and exp claims if they are present.
763
- * @param verifier
764
- * @param options - Options for verification, such as current date and skew seconds
765
- * @returns
766
- */
767
- verify(verifier, options) {
768
- return __async(this, null, function* () {
769
- var _a;
770
- const alg = (_a = this.header) == null ? void 0 : _a.alg;
771
- if (typeof alg !== "string" || alg === "none") {
772
- throw new SDJWTException('Verify Error: alg "none" is not allowed');
773
- }
774
- if ((options == null ? void 0 : options.allowedIssuerAlgorithms) && !options.allowedIssuerAlgorithms.includes(alg)) {
775
- throw new SDJWTException(`Verify Error: Disallowed alg ${alg}`);
776
- }
777
- if (!(options == null ? void 0 : options.skipJwtClaimValidation)) {
778
- validateJwtPayload(this.payload, options);
779
- }
780
- if (!this.signature) {
781
- throw new SDJWTException("Verify Error: no signature in JWT");
782
- }
783
- const data = this.getUnsignedToken();
784
- const verified = yield verifier(data, this.signature, options);
785
- if (!verified) {
786
- throw new SDJWTException("Verify Error: Invalid JWT Signature");
787
- }
788
- return { payload: this.payload, header: this.header };
789
- });
790
- }
503
+ //#endregion
504
+ //#region src/jwt.ts
505
+ const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
506
+ const validateNumericDate = (payload, claim) => {
507
+ const value = payload[claim];
508
+ if (value === void 0) return void 0;
509
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new SDJWTException(`Verify Error: JWT ${claim} must be a number`);
510
+ return value;
791
511
  };
792
-
793
- // src/kbjwt.ts
794
- var KBJwt = class _KBJwt extends Jwt {
795
- // Checking the validity of the key binding jwt
796
- // the type unknown is not good, but we don't know at this point how to get the public key of the signer, this is defined in the kbVerifier
797
- verifyKB(values) {
798
- return __async(this, null, function* () {
799
- var _a, _b, _c, _d;
800
- if (!this.header || !this.payload || !this.signature) {
801
- throw new SDJWTException("Verify Error: Invalid JWT");
802
- }
803
- if (typeof this.header.alg !== "string" || this.header.alg === "none" || typeof this.header.typ !== "string" || this.header.typ !== KB_JWT_TYP || typeof this.payload.iat !== "number" || typeof this.payload.aud !== "string" || typeof this.payload.nonce !== "string" || typeof this.payload.sd_hash !== "string" || this.payload.sd_hash.length === 0) {
804
- throw new SDJWTException("Invalid Key Binding Jwt");
805
- }
806
- if (this.payload.nonce !== values.nonce) {
807
- throw new SDJWTException("Verify Error: Invalid Nonce");
808
- }
809
- if (((_a = values.options) == null ? void 0 : _a.expectedKeyBindingAudience) !== void 0) {
810
- const expectedAudiences = Array.isArray(
811
- values.options.expectedKeyBindingAudience
812
- ) ? values.options.expectedKeyBindingAudience : [values.options.expectedKeyBindingAudience];
813
- if (!expectedAudiences.includes(this.payload.aud)) {
814
- throw new SDJWTException("Verify Error: Invalid Key Binding audience");
815
- }
816
- }
817
- if (((_b = values.options) == null ? void 0 : _b.keyBindingMaxAgeSeconds) !== void 0) {
818
- const currentDate = (_c = values.options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
819
- const skew = (_d = values.options.skewSeconds) != null ? _d : 0;
820
- if (this.payload.iat + values.options.keyBindingMaxAgeSeconds + skew < currentDate) {
821
- throw new SDJWTException("Verify Error: Key Binding JWT is too old");
822
- }
823
- }
824
- yield this.verify(
825
- (data, sig) => values.verifier(data, sig, values.payload),
826
- values.options
827
- );
828
- return { payload: this.payload, header: this.header };
829
- });
830
- }
831
- // This function is for creating KBJwt object for verify properly
832
- static fromKBEncode(encodedJwt) {
833
- const { header, payload, signature } = Jwt.decodeJWT(
834
- encodedJwt
835
- );
836
- const jwt = new _KBJwt({
837
- header,
838
- payload,
839
- signature,
840
- encoded: encodedJwt
841
- });
842
- return jwt;
843
- }
512
+ const getAudiences = (audience) => {
513
+ if (typeof audience === "string") return [audience];
514
+ if (isStringArray(audience)) return audience;
844
515
  };
845
-
846
- // src/decoy.ts
847
- var createDecoy = (hash, saltGenerator) => __async(null, null, function* () {
848
- const { hasher, alg } = hash;
849
- const salt = yield saltGenerator(16);
850
- const decoy = yield hasher(salt, alg);
851
- return uint8ArrayToBase64Url(decoy);
852
- });
853
-
854
- // src/present/present.ts
855
- var presentableKeys = (rawPayload, disclosures, hasher) => __async(null, null, function* () {
856
- const { disclosureKeymap } = yield unpack(rawPayload, disclosures, hasher);
857
- return Object.keys(disclosureKeymap).sort();
858
- });
859
- var presentableKeysSync = (rawPayload, disclosures, hasher) => {
860
- const { disclosureKeymap } = unpackSync(rawPayload, disclosures, hasher);
861
- return Object.keys(disclosureKeymap).sort();
516
+ const validateAudience = (payload, expectedAudience) => {
517
+ if (expectedAudience === void 0) return;
518
+ const expectedAudiences = Array.isArray(expectedAudience) ? expectedAudience : [expectedAudience];
519
+ const audiences = getAudiences(payload.aud);
520
+ if (!audiences || !expectedAudiences.some((expected) => audiences.includes(expected))) throw new SDJWTException("Verify Error: Invalid audience");
862
521
  };
863
- var present = (sdJwt, presentFrame, hasher) => __async(null, null, function* () {
864
- const { jwt, kbJwt } = splitSdJwt(sdJwt);
865
- const {
866
- jwt: { payload },
867
- disclosures
868
- } = yield decodeSdJwt(sdJwt, hasher);
869
- const { _sd_alg: alg } = getSDAlgAndPayload(payload);
870
- const hash = { alg, hasher };
871
- const keys = transformPresentationFrame(presentFrame);
872
- const hashmap = yield createHashMapping(disclosures, hash);
873
- const { disclosureKeymap } = yield unpack(payload, disclosures, hasher);
874
- const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
875
- return [
876
- jwt,
877
- ...presentedDisclosures.map((d) => d.encode()),
878
- kbJwt != null ? kbJwt : ""
879
- ].join(SD_SEPARATOR);
880
- });
881
- var presentSync = (sdJwt, presentFrame, hasher) => {
882
- const { jwt, kbJwt } = splitSdJwt(sdJwt);
883
- const {
884
- jwt: { payload },
885
- disclosures
886
- } = decodeSdJwtSync(sdJwt, hasher);
887
- const { _sd_alg: alg } = getSDAlgAndPayload(payload);
888
- const hash = { alg, hasher };
889
- const keys = transformPresentationFrame(presentFrame);
890
- const hashmap = createHashMappingSync(disclosures, hash);
891
- const { disclosureKeymap } = unpackSync(payload, disclosures, hasher);
892
- const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
893
- return [
894
- jwt,
895
- ...presentedDisclosures.map((d) => d.encode()),
896
- kbJwt != null ? kbJwt : ""
897
- ].join(SD_SEPARATOR);
522
+ const validateJwtPayload = (payload, options) => {
523
+ if (!payload) throw new SDJWTException("Verify Error: JWT payload is missing");
524
+ const skew = options?.skewSeconds ? options.skewSeconds : 0;
525
+ const currentDate = options?.currentDate ?? nowInSeconds();
526
+ const iat = validateNumericDate(payload, "iat");
527
+ const nbf = validateNumericDate(payload, "nbf");
528
+ const exp = validateNumericDate(payload, "exp");
529
+ if (iat !== void 0 && iat - skew > currentDate) throw new SDJWTException("Verify Error: JWT is not yet valid");
530
+ if (nbf !== void 0 && nbf - skew > currentDate) throw new SDJWTException("Verify Error: JWT is not yet valid");
531
+ if (exp !== void 0 && exp + skew <= currentDate) throw new SDJWTException("Verify Error: JWT is expired");
532
+ validateAudience(payload, options?.expectedAudience);
898
533
  };
899
- var transformPresentationFrame = (obj, prefix = []) => {
900
- return Object.entries(obj).reduce((acc, [key, value]) => {
901
- const newPrefix = [...prefix, key];
902
- const encodedPrefix = encodePath(newPrefix);
903
- if (typeof value === "boolean") {
904
- if (value) {
905
- acc.push(encodedPrefix);
906
- }
907
- } else if (typeof value === "object" && value !== null) {
908
- acc.push(
909
- encodedPrefix,
910
- ...transformPresentationFrame(
911
- value,
912
- newPrefix
913
- )
914
- );
915
- }
916
- return acc;
917
- }, []);
534
+ var Jwt = class Jwt {
535
+ constructor(data) {
536
+ this.header = data?.header;
537
+ this.payload = data?.payload;
538
+ this.signature = data?.signature;
539
+ this.encoded = data?.encoded;
540
+ }
541
+ static decodeJWT(jwt) {
542
+ return decodeJwt(jwt);
543
+ }
544
+ static fromEncode(encodedJwt) {
545
+ const { header, payload, signature } = Jwt.decodeJWT(encodedJwt);
546
+ return new Jwt({
547
+ header,
548
+ payload,
549
+ signature,
550
+ encoded: encodedJwt
551
+ });
552
+ }
553
+ setHeader(header) {
554
+ this.header = header;
555
+ this.encoded = void 0;
556
+ return this;
557
+ }
558
+ setPayload(payload) {
559
+ this.payload = payload;
560
+ this.encoded = void 0;
561
+ return this;
562
+ }
563
+ getUnsignedToken() {
564
+ if (!this.header || !this.payload) throw new SDJWTException("Serialize Error: Invalid JWT");
565
+ if (this.encoded) {
566
+ const parts = this.encoded.split(".");
567
+ if (parts.length !== 3) throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
568
+ return parts.slice(0, 2).join(".");
569
+ }
570
+ return `${base64urlEncode(JSON.stringify(this.header))}.${base64urlEncode(JSON.stringify(this.payload))}`;
571
+ }
572
+ async sign(signer) {
573
+ if (!this.header || this.header.alg === "none") throw new SDJWTException("Sign Error: alg \"none\" is not allowed");
574
+ const data = this.getUnsignedToken();
575
+ this.signature = await signer(data);
576
+ return this.encodeJwt();
577
+ }
578
+ encodeJwt() {
579
+ if (this.encoded) return this.encoded;
580
+ if (!this.header || !this.payload || !this.signature) throw new SDJWTException("Serialize Error: Invalid JWT");
581
+ const compact = `${base64urlEncode(JSON.stringify(this.header))}.${base64urlEncode(JSON.stringify(this.payload))}.${this.signature}`;
582
+ this.encoded = compact;
583
+ return compact;
584
+ }
585
+ /**
586
+ * Verify the JWT using the provided verifier function.
587
+ * It checks the signature and validates the iat, nbf, and exp claims if they are present.
588
+ * @param verifier
589
+ * @param options - Options for verification, such as current date and skew seconds
590
+ * @returns
591
+ */
592
+ async verify(verifier, options) {
593
+ const alg = this.header?.alg;
594
+ if (typeof alg !== "string" || alg === "none") throw new SDJWTException("Verify Error: alg \"none\" is not allowed");
595
+ if (options?.allowedIssuerAlgorithms && !options.allowedIssuerAlgorithms.includes(alg)) throw new SDJWTException(`Verify Error: Disallowed alg ${alg}`);
596
+ if (!options?.skipJwtClaimValidation) validateJwtPayload(this.payload, options);
597
+ if (!this.signature) throw new SDJWTException("Verify Error: no signature in JWT");
598
+ if (!await verifier(this.getUnsignedToken(), this.signature, options)) throw new SDJWTException("Verify Error: Invalid JWT Signature");
599
+ return {
600
+ payload: this.payload,
601
+ header: this.header
602
+ };
603
+ }
918
604
  };
919
- var createHashMappingForSerializedDisclosure = (disclosures) => {
920
- const map = {};
921
- for (let i = 0; i < disclosures.length; i++) {
922
- const disclosure = disclosures[i];
923
- const { digest, encoded, key, salt, value } = disclosure;
924
- map[digest] = Disclosure.fromArray(
925
- key ? [salt, key, value] : [salt, value],
926
- { digest, encoded }
927
- );
928
- }
929
- return map;
605
+ //#endregion
606
+ //#region src/kbjwt.ts
607
+ var KBJwt = class KBJwt extends Jwt {
608
+ async verifyKB(values) {
609
+ if (!this.header || !this.payload || !this.signature) throw new SDJWTException("Verify Error: Invalid JWT");
610
+ if (typeof this.header.alg !== "string" || this.header.alg === "none" || typeof this.header.typ !== "string" || this.header.typ !== "kb+jwt" || typeof this.payload.iat !== "number" || typeof this.payload.aud !== "string" || typeof this.payload.nonce !== "string" || typeof this.payload.sd_hash !== "string" || this.payload.sd_hash.length === 0) throw new SDJWTException("Invalid Key Binding Jwt");
611
+ if (this.payload.nonce !== values.nonce) throw new SDJWTException("Verify Error: Invalid Nonce");
612
+ if (values.options?.expectedKeyBindingAudience !== void 0) {
613
+ if (!(Array.isArray(values.options.expectedKeyBindingAudience) ? values.options.expectedKeyBindingAudience : [values.options.expectedKeyBindingAudience]).includes(this.payload.aud)) throw new SDJWTException("Verify Error: Invalid Key Binding audience");
614
+ }
615
+ if (values.options?.keyBindingMaxAgeSeconds !== void 0) {
616
+ const currentDate = values.options.currentDate ?? nowInSeconds();
617
+ const skew = values.options.skewSeconds ?? 0;
618
+ if (this.payload.iat + values.options.keyBindingMaxAgeSeconds + skew < currentDate) throw new SDJWTException("Verify Error: Key Binding JWT is too old");
619
+ }
620
+ await this.verify((data, sig) => values.verifier(data, sig, values.payload), values.options);
621
+ return {
622
+ payload: this.payload,
623
+ header: this.header
624
+ };
625
+ }
626
+ static fromKBEncode(encodedJwt) {
627
+ const { header, payload, signature } = Jwt.decodeJWT(encodedJwt);
628
+ return new KBJwt({
629
+ header,
630
+ payload,
631
+ signature,
632
+ encoded: encodedJwt
633
+ });
634
+ }
930
635
  };
931
- var selectDisclosures = (payload, disclosures, presentationFrame) => {
932
- if (disclosures.length === 0) {
933
- return [];
934
- }
935
- const hashmap = createHashMappingForSerializedDisclosure(disclosures);
936
- const { disclosureKeymap } = unpackObj(payload, hashmap);
937
- const keys = transformPresentationFrame(presentationFrame);
938
- const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
939
- const selectedDisclosures = presentedDisclosures.map(
940
- (d) => {
941
- const { salt, key, value, _digest } = d;
942
- if (!_digest) {
943
- throw new SDJWTException(
944
- "Implementation error: _digest is not defined"
945
- );
946
- }
947
- return {
948
- digest: _digest,
949
- encoded: d.encode(),
950
- salt,
951
- key,
952
- value
953
- };
954
- }
955
- );
956
- return selectedDisclosures;
636
+ //#endregion
637
+ //#region src/decoy.ts
638
+ const createDecoy = async (hash, saltGenerator) => {
639
+ const { hasher, alg } = hash;
640
+ const decoy = await hasher(await saltGenerator(16), alg);
641
+ return uint8ArrayToBase64Url(decoy);
957
642
  };
958
-
959
- // src/sdjwt.ts
960
- var createDisclosureSalt = (saltGenerator, seenSalts) => __async(null, null, function* () {
961
- const salt = yield saltGenerator(16);
962
- if (typeof salt !== "string") {
963
- throw new SDJWTException("SaltGenerator must return a string");
964
- }
965
- if (seenSalts.has(salt)) {
966
- throw new SDJWTException("Duplicate disclosure salt detected");
967
- }
968
- seenSalts.add(salt);
969
- return salt;
970
- });
971
- var addDisclosureDigest = (digest, seenDigests) => {
972
- if (seenDigests.has(digest)) {
973
- throw new SDJWTException("Duplicate disclosure digest detected");
974
- }
975
- seenDigests.add(digest);
643
+ //#endregion
644
+ //#region src/present/present.ts
645
+ const presentableKeys = async (rawPayload, disclosures, hasher) => {
646
+ const { disclosureKeymap } = await unpack(rawPayload, disclosures, hasher);
647
+ return Object.keys(disclosureKeymap).sort();
976
648
  };
977
- var SDJwt = class _SDJwt {
978
- constructor(data) {
979
- this.jwt = data == null ? void 0 : data.jwt;
980
- this.disclosures = data == null ? void 0 : data.disclosures;
981
- this.kbJwt = data == null ? void 0 : data.kbJwt;
982
- }
983
- static decodeSDJwt(sdjwt, hasher) {
984
- return __async(this, null, function* () {
985
- const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
986
- if (encodedDisclosures.length === 0) {
987
- throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
988
- }
989
- const jwt = Jwt.fromEncode(encodedJwt);
990
- if (!jwt.payload) {
991
- throw new Error("Payload is undefined on the JWT. Invalid state reached");
992
- }
993
- const encodedKeyBindingJwt = encodedDisclosures.pop();
994
- const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
995
- const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
996
- const disclosures = yield Promise.all(
997
- encodedDisclosures.map(
998
- (ed) => Disclosure.fromEncode(ed, { alg: _sd_alg, hasher })
999
- )
1000
- );
1001
- return {
1002
- jwt,
1003
- disclosures,
1004
- kbJwt
1005
- };
1006
- });
1007
- }
1008
- static extractJwt(encodedSdJwt) {
1009
- return __async(this, null, function* () {
1010
- const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split(SD_SEPARATOR);
1011
- return Jwt.fromEncode(encodedJwt);
1012
- });
1013
- }
1014
- static fromEncode(encodedSdJwt, hasher) {
1015
- return __async(this, null, function* () {
1016
- const { jwt, disclosures, kbJwt } = yield _SDJwt.decodeSDJwt(encodedSdJwt, hasher);
1017
- return new _SDJwt({
1018
- jwt,
1019
- disclosures,
1020
- kbJwt
1021
- });
1022
- });
1023
- }
1024
- present(presentFrame, hasher) {
1025
- return __async(this, null, function* () {
1026
- const disclosures = yield this.getPresentDisclosures(presentFrame, hasher);
1027
- const presentSDJwt = new _SDJwt({
1028
- jwt: this.jwt,
1029
- disclosures,
1030
- kbJwt: this.kbJwt
1031
- });
1032
- return presentSDJwt.encodeSDJwt();
1033
- });
1034
- }
1035
- getPresentDisclosures(presentFrame, hasher) {
1036
- return __async(this, null, function* () {
1037
- var _a;
1038
- if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
1039
- throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
1040
- }
1041
- const { _sd_alg: alg } = getSDAlgAndPayload(this.jwt.payload);
1042
- const hash = { alg, hasher };
1043
- const hashmap = yield createHashMapping(this.disclosures, hash);
1044
- const { disclosureKeymap } = yield unpack(
1045
- this.jwt.payload,
1046
- this.disclosures,
1047
- hasher
1048
- );
1049
- const keys = presentFrame ? transformPresentationFrame(presentFrame) : yield this.presentableKeys(hasher);
1050
- const disclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
1051
- return disclosures;
1052
- });
1053
- }
1054
- encodeSDJwt() {
1055
- const data = [];
1056
- if (!this.jwt) {
1057
- throw new SDJWTException("Invalid sd-jwt: jwt is missing");
1058
- }
1059
- const encodedJwt = this.jwt.encodeJwt();
1060
- data.push(encodedJwt);
1061
- if (this.disclosures && this.disclosures.length > 0) {
1062
- const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join(SD_SEPARATOR);
1063
- data.push(encodeddisclosures);
1064
- }
1065
- data.push(this.kbJwt ? this.kbJwt.encodeJwt() : "");
1066
- return data.join(SD_SEPARATOR);
1067
- }
1068
- keys(hasher) {
1069
- return __async(this, null, function* () {
1070
- return listKeys(yield this.getClaims(hasher)).sort();
1071
- });
1072
- }
1073
- presentableKeys(hasher) {
1074
- return __async(this, null, function* () {
1075
- var _a, _b;
1076
- if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
1077
- throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
1078
- }
1079
- const { disclosureKeymap } = yield unpack(
1080
- (_b = this.jwt) == null ? void 0 : _b.payload,
1081
- this.disclosures,
1082
- hasher
1083
- );
1084
- return Object.keys(disclosureKeymap).sort();
1085
- });
1086
- }
1087
- getClaims(hasher) {
1088
- return __async(this, null, function* () {
1089
- var _a;
1090
- if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
1091
- throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
1092
- }
1093
- const { unpackedObj } = yield unpack(
1094
- this.jwt.payload,
1095
- this.disclosures,
1096
- hasher
1097
- );
1098
- return unpackedObj;
1099
- });
1100
- }
649
+ const presentableKeysSync = (rawPayload, disclosures, hasher) => {
650
+ const { disclosureKeymap } = unpackSync(rawPayload, disclosures, hasher);
651
+ return Object.keys(disclosureKeymap).sort();
1101
652
  };
1102
- var listKeys = (obj, prefix = "") => {
1103
- const keys = [];
1104
- for (const key in obj) {
1105
- if (obj[key] === void 0) continue;
1106
- const escapedKey = encodePathSegment(key);
1107
- const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
1108
- keys.push(newKey);
1109
- const value = obj[key];
1110
- if (value && typeof value === "object") {
1111
- keys.push(...listKeys(value, newKey));
1112
- }
1113
- }
1114
- return keys;
653
+ const present = async (sdJwt, presentFrame, hasher) => {
654
+ const { jwt, kbJwt } = splitSdJwt(sdJwt);
655
+ const { jwt: { payload }, disclosures } = await decodeSdJwt(sdJwt, hasher);
656
+ const { _sd_alg: alg } = getSDAlgAndPayload(payload);
657
+ const hash = {
658
+ alg,
659
+ hasher
660
+ };
661
+ const keys = transformPresentationFrame(presentFrame);
662
+ const hashmap = await createHashMapping(disclosures, hash);
663
+ const { disclosureKeymap } = await unpack(payload, disclosures, hasher);
664
+ return [
665
+ jwt,
666
+ ...keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => d.encode()),
667
+ kbJwt ?? ""
668
+ ].join("~");
1115
669
  };
1116
- var pack = (_0, _1, _2, _3, ..._4) => __async(null, [_0, _1, _2, _3, ..._4], function* (claims, disclosureFrame, hash, saltGenerator, seenSalts = /* @__PURE__ */ new Set(), seenDigests = /* @__PURE__ */ new Set()) {
1117
- var _a, _b;
1118
- if (!disclosureFrame) {
1119
- return {
1120
- packedClaims: claims,
1121
- disclosures: []
1122
- };
1123
- }
1124
- const sd = (_a = disclosureFrame[SD_DIGEST]) != null ? _a : [];
1125
- const decoyCount = (_b = disclosureFrame[SD_DECOY]) != null ? _b : 0;
1126
- if (Array.isArray(claims)) {
1127
- const packedClaims2 = [];
1128
- const disclosures2 = [];
1129
- const recursivePackedClaims2 = {};
1130
- for (const key in disclosureFrame) {
1131
- if (key !== SD_DIGEST) {
1132
- const idx = Number.parseInt(key, 10);
1133
- const packed = yield pack(
1134
- claims[idx],
1135
- disclosureFrame[idx],
1136
- hash,
1137
- saltGenerator,
1138
- seenSalts,
1139
- seenDigests
1140
- );
1141
- recursivePackedClaims2[idx] = packed.packedClaims;
1142
- disclosures2.push(...packed.disclosures);
1143
- }
1144
- }
1145
- for (let i = 0; i < claims.length; i++) {
1146
- const claim = recursivePackedClaims2[i] ? recursivePackedClaims2[i] : claims[i];
1147
- if (sd.includes(i)) {
1148
- const salt = yield createDisclosureSalt(saltGenerator, seenSalts);
1149
- const disclosure = new Disclosure([salt, claim]);
1150
- const digest = yield disclosure.digest(hash);
1151
- addDisclosureDigest(digest, seenDigests);
1152
- packedClaims2.push({ [SD_LIST_KEY]: digest });
1153
- disclosures2.push(disclosure);
1154
- } else {
1155
- packedClaims2.push(claim);
1156
- }
1157
- }
1158
- for (let j = 0; j < decoyCount; j++) {
1159
- const decoyDigest = yield createDecoy(hash, saltGenerator);
1160
- addDisclosureDigest(decoyDigest, seenDigests);
1161
- packedClaims2.push({ [SD_LIST_KEY]: decoyDigest });
1162
- }
1163
- return { packedClaims: packedClaims2, disclosures: disclosures2 };
1164
- }
1165
- const packedClaims = {};
1166
- const disclosures = [];
1167
- const recursivePackedClaims = {};
1168
- for (const key in disclosureFrame) {
1169
- if (key !== SD_DIGEST) {
1170
- const packed = yield pack(
1171
- // @ts-expect-error
1172
- claims[key],
1173
- disclosureFrame[key],
1174
- hash,
1175
- saltGenerator,
1176
- seenSalts,
1177
- seenDigests
1178
- );
1179
- recursivePackedClaims[key] = packed.packedClaims;
1180
- disclosures.push(...packed.disclosures);
1181
- }
1182
- }
1183
- const _sd = [];
1184
- for (const key in claims) {
1185
- const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
1186
- if (sd.includes(key)) {
1187
- const salt = yield createDisclosureSalt(saltGenerator, seenSalts);
1188
- const disclosure = new Disclosure([salt, key, claim]);
1189
- const digest = yield disclosure.digest(hash);
1190
- addDisclosureDigest(digest, seenDigests);
1191
- _sd.push(digest);
1192
- disclosures.push(disclosure);
1193
- } else {
1194
- packedClaims[key] = claim;
1195
- }
1196
- }
1197
- for (let j = 0; j < decoyCount; j++) {
1198
- const decoyDigest = yield createDecoy(hash, saltGenerator);
1199
- addDisclosureDigest(decoyDigest, seenDigests);
1200
- _sd.push(decoyDigest);
1201
- }
1202
- if (_sd.length > 0) {
1203
- packedClaims[SD_DIGEST] = _sd.sort();
1204
- }
1205
- return { packedClaims, disclosures };
1206
- });
1207
-
1208
- // src/index.ts
670
+ const presentSync = (sdJwt, presentFrame, hasher) => {
671
+ const { jwt, kbJwt } = splitSdJwt(sdJwt);
672
+ const { jwt: { payload }, disclosures } = decodeSdJwtSync(sdJwt, hasher);
673
+ const { _sd_alg: alg } = getSDAlgAndPayload(payload);
674
+ const hash = {
675
+ alg,
676
+ hasher
677
+ };
678
+ const keys = transformPresentationFrame(presentFrame);
679
+ const hashmap = createHashMappingSync(disclosures, hash);
680
+ const { disclosureKeymap } = unpackSync(payload, disclosures, hasher);
681
+ return [
682
+ jwt,
683
+ ...keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => d.encode()),
684
+ kbJwt ?? ""
685
+ ].join("~");
686
+ };
687
+ /**
688
+ * Transform the object keys into an array of strings. We are not sorting the array in any way.
689
+ * @param obj The object to transform
690
+ * @param prefix The prefix to add to the keys
691
+ * @returns
692
+ */
693
+ const transformPresentationFrame = (obj, prefix = []) => {
694
+ return Object.entries(obj).reduce((acc, [key, value]) => {
695
+ const newPrefix = [...prefix, key];
696
+ const encodedPrefix = encodePath(newPrefix);
697
+ if (typeof value === "boolean") {
698
+ if (value) acc.push(encodedPrefix);
699
+ } else if (typeof value === "object" && value !== null) acc.push(encodedPrefix, ...transformPresentationFrame(value, newPrefix));
700
+ return acc;
701
+ }, []);
702
+ };
703
+ const createHashMappingForSerializedDisclosure = (disclosures) => {
704
+ const map = {};
705
+ for (let i = 0; i < disclosures.length; i++) {
706
+ const { digest, encoded, key, salt, value } = disclosures[i];
707
+ map[digest] = Disclosure.fromArray(key ? [
708
+ salt,
709
+ key,
710
+ value
711
+ ] : [salt, value], {
712
+ digest,
713
+ encoded
714
+ });
715
+ }
716
+ return map;
717
+ };
718
+ /**
719
+ * This function selects the serialized disclosures from the payload
720
+ * and array of serialized disclosure based on the presentation frame.
721
+ * If you want to know what is serialized disclosures, check type SerializedDisclosure.
722
+ * @param payload: Record<string, unknown>
723
+ * @param disclosures: SerializedDisclosure[]
724
+ * @param presentationFrame: PresentationFrame<T>
725
+ */
726
+ const selectDisclosures = (payload, disclosures, presentationFrame) => {
727
+ if (disclosures.length === 0) return [];
728
+ const hashmap = createHashMappingForSerializedDisclosure(disclosures);
729
+ const { disclosureKeymap } = unpackObj(payload, hashmap);
730
+ return transformPresentationFrame(presentationFrame).map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => {
731
+ const { salt, key, value, _digest } = d;
732
+ if (!_digest) throw new SDJWTException("Implementation error: _digest is not defined");
733
+ return {
734
+ digest: _digest,
735
+ encoded: d.encode(),
736
+ salt,
737
+ key,
738
+ value
739
+ };
740
+ });
741
+ };
742
+ //#endregion
743
+ //#region src/sdjwt.ts
744
+ const createDisclosureSalt = async (saltGenerator, seenSalts) => {
745
+ const salt = await saltGenerator(16);
746
+ if (typeof salt !== "string") throw new SDJWTException("SaltGenerator must return a string");
747
+ if (seenSalts.has(salt)) throw new SDJWTException("Duplicate disclosure salt detected");
748
+ seenSalts.add(salt);
749
+ return salt;
750
+ };
751
+ const addDisclosureDigest = (digest, seenDigests) => {
752
+ if (seenDigests.has(digest)) throw new SDJWTException("Duplicate disclosure digest detected");
753
+ seenDigests.add(digest);
754
+ };
755
+ var SDJwt = class SDJwt {
756
+ constructor(data) {
757
+ this.jwt = data?.jwt;
758
+ this.disclosures = data?.disclosures;
759
+ this.kbJwt = data?.kbJwt;
760
+ }
761
+ static async decodeSDJwt(sdjwt, hasher) {
762
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
763
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
764
+ const jwt = Jwt.fromEncode(encodedJwt);
765
+ if (!jwt.payload) throw new Error("Payload is undefined on the JWT. Invalid state reached");
766
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
767
+ const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
768
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
769
+ return {
770
+ jwt,
771
+ disclosures: await Promise.all(encodedDisclosures.map((ed) => Disclosure.fromEncode(ed, {
772
+ alg: _sd_alg,
773
+ hasher
774
+ }))),
775
+ kbJwt
776
+ };
777
+ }
778
+ static async extractJwt(encodedSdJwt) {
779
+ const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split("~");
780
+ return Jwt.fromEncode(encodedJwt);
781
+ }
782
+ static async fromEncode(encodedSdJwt, hasher) {
783
+ const { jwt, disclosures, kbJwt } = await SDJwt.decodeSDJwt(encodedSdJwt, hasher);
784
+ return new SDJwt({
785
+ jwt,
786
+ disclosures,
787
+ kbJwt
788
+ });
789
+ }
790
+ async present(presentFrame, hasher) {
791
+ const disclosures = await this.getPresentDisclosures(presentFrame, hasher);
792
+ return new SDJwt({
793
+ jwt: this.jwt,
794
+ disclosures,
795
+ kbJwt: this.kbJwt
796
+ }).encodeSDJwt();
797
+ }
798
+ async getPresentDisclosures(presentFrame, hasher) {
799
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
800
+ const { _sd_alg: alg } = getSDAlgAndPayload(this.jwt.payload);
801
+ const hash = {
802
+ alg,
803
+ hasher
804
+ };
805
+ const hashmap = await createHashMapping(this.disclosures, hash);
806
+ const { disclosureKeymap } = await unpack(this.jwt.payload, this.disclosures, hasher);
807
+ return (presentFrame ? transformPresentationFrame(presentFrame) : await this.presentableKeys(hasher)).map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
808
+ }
809
+ encodeSDJwt() {
810
+ const data = [];
811
+ if (!this.jwt) throw new SDJWTException("Invalid sd-jwt: jwt is missing");
812
+ const encodedJwt = this.jwt.encodeJwt();
813
+ data.push(encodedJwt);
814
+ if (this.disclosures && this.disclosures.length > 0) {
815
+ const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join("~");
816
+ data.push(encodeddisclosures);
817
+ }
818
+ data.push(this.kbJwt ? this.kbJwt.encodeJwt() : "");
819
+ return data.join("~");
820
+ }
821
+ async keys(hasher) {
822
+ return listKeys(await this.getClaims(hasher)).sort();
823
+ }
824
+ async presentableKeys(hasher) {
825
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
826
+ const { disclosureKeymap } = await unpack(this.jwt?.payload, this.disclosures, hasher);
827
+ return Object.keys(disclosureKeymap).sort();
828
+ }
829
+ async getClaims(hasher) {
830
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
831
+ const { unpackedObj } = await unpack(this.jwt.payload, this.disclosures, hasher);
832
+ return unpackedObj;
833
+ }
834
+ };
835
+ const listKeys = (obj, prefix = "") => {
836
+ const keys = [];
837
+ for (const key in obj) {
838
+ if (obj[key] === void 0) continue;
839
+ const escapedKey = encodePathSegment(key);
840
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
841
+ keys.push(newKey);
842
+ const value = obj[key];
843
+ if (value && typeof value === "object") keys.push(...listKeys(value, newKey));
844
+ }
845
+ return keys;
846
+ };
847
+ const pack = async (claims, disclosureFrame, hash, saltGenerator, seenSalts = /* @__PURE__ */ new Set(), seenDigests = /* @__PURE__ */ new Set()) => {
848
+ if (!disclosureFrame) return {
849
+ packedClaims: claims,
850
+ disclosures: []
851
+ };
852
+ const sd = disclosureFrame["_sd"] ?? [];
853
+ const decoyCount = disclosureFrame["_sd_decoy"] ?? 0;
854
+ if (Array.isArray(claims)) {
855
+ const packedClaims = [];
856
+ const disclosures = [];
857
+ const recursivePackedClaims = {};
858
+ for (const key in disclosureFrame) if (key !== "_sd") {
859
+ const idx = Number.parseInt(key, 10);
860
+ const packed = await pack(claims[idx], disclosureFrame[idx], hash, saltGenerator, seenSalts, seenDigests);
861
+ recursivePackedClaims[idx] = packed.packedClaims;
862
+ disclosures.push(...packed.disclosures);
863
+ }
864
+ for (let i = 0; i < claims.length; i++) {
865
+ const claim = recursivePackedClaims[i] ? recursivePackedClaims[i] : claims[i];
866
+ /** This part is set discloure for array items.
867
+ * The example of disclosureFrame of an Array is
868
+ *
869
+ * const claims = {
870
+ * array: ['a', 'b', 'c']
871
+ * }
872
+ *
873
+ * diclosureFrame: DisclosureFrame<typeof claims> = {
874
+ * array: {
875
+ * _sd: [0, 2]
876
+ * }
877
+ * }
878
+ *
879
+ * It means that we want to disclose the first and the third item of the array
880
+ *
881
+ * So If the index `i` is in the disclosure list(sd), then we create a disclosure for the claim
882
+ */
883
+ if (sd.includes(i)) {
884
+ const disclosure = new Disclosure([await createDisclosureSalt(saltGenerator, seenSalts), claim]);
885
+ const digest = await disclosure.digest(hash);
886
+ addDisclosureDigest(digest, seenDigests);
887
+ packedClaims.push({ ["..."]: digest });
888
+ disclosures.push(disclosure);
889
+ } else packedClaims.push(claim);
890
+ }
891
+ for (let j = 0; j < decoyCount; j++) {
892
+ const decoyDigest = await createDecoy(hash, saltGenerator);
893
+ addDisclosureDigest(decoyDigest, seenDigests);
894
+ packedClaims.push({ ["..."]: decoyDigest });
895
+ }
896
+ return {
897
+ packedClaims,
898
+ disclosures
899
+ };
900
+ }
901
+ const packedClaims = {};
902
+ const disclosures = [];
903
+ const recursivePackedClaims = {};
904
+ for (const key in disclosureFrame) if (key !== "_sd") {
905
+ const packed = await pack(claims[key], disclosureFrame[key], hash, saltGenerator, seenSalts, seenDigests);
906
+ recursivePackedClaims[key] = packed.packedClaims;
907
+ disclosures.push(...packed.disclosures);
908
+ }
909
+ const _sd = [];
910
+ for (const key in claims) {
911
+ const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
912
+ if (sd.includes(key)) {
913
+ const disclosure = new Disclosure([
914
+ await createDisclosureSalt(saltGenerator, seenSalts),
915
+ key,
916
+ claim
917
+ ]);
918
+ const digest = await disclosure.digest(hash);
919
+ addDisclosureDigest(digest, seenDigests);
920
+ _sd.push(digest);
921
+ disclosures.push(disclosure);
922
+ } else packedClaims[key] = claim;
923
+ }
924
+ for (let j = 0; j < decoyCount; j++) {
925
+ const decoyDigest = await createDecoy(hash, saltGenerator);
926
+ addDisclosureDigest(decoyDigest, seenDigests);
927
+ _sd.push(decoyDigest);
928
+ }
929
+ if (_sd.length > 0) packedClaims["_sd"] = _sd.sort();
930
+ return {
931
+ packedClaims,
932
+ disclosures
933
+ };
934
+ };
935
+ //#endregion
936
+ //#region src/index.ts
937
+ /**
938
+ * Internal utility function to validate that a payload does not contain reserved field names.
939
+ */
1209
940
  function validateReservedFieldsInternal(payload) {
1210
- const reservedFields = /* @__PURE__ */ new Set([SD_DIGEST, "_sd_alg", SD_DECOY, SD_LIST_KEY]);
1211
- const visit = (node) => {
1212
- if (!node || typeof node !== "object") {
1213
- return;
1214
- }
1215
- for (const [key, value] of Object.entries(
1216
- node
1217
- )) {
1218
- if (reservedFields.has(key)) {
1219
- throw new SDJWTException(`Reserved field name "${key}" is not allowed`);
1220
- }
1221
- visit(value);
1222
- }
1223
- };
1224
- visit(payload);
941
+ const reservedFields = /* @__PURE__ */ new Set([
942
+ "_sd",
943
+ "_sd_alg",
944
+ SD_DECOY,
945
+ "..."
946
+ ]);
947
+ const visit = (node) => {
948
+ if (!node || typeof node !== "object") return;
949
+ for (const [key, value] of Object.entries(node)) {
950
+ if (reservedFields.has(key)) throw new SDJWTException(`Reserved field name "${key}" is not allowed`);
951
+ visit(value);
952
+ }
953
+ };
954
+ visit(payload);
1225
955
  }
1226
- var _SDJwtInstance = class _SDJwtInstance {
1227
- constructor(userConfig) {
1228
- this.userConfig = {};
1229
- var _a;
1230
- if (userConfig) {
1231
- if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
1232
- throw new SDJWTException(
1233
- `Invalid hash algorithm: ${userConfig.hashAlg}`
1234
- );
1235
- }
1236
- const allowedDisclosureHashAlgorithms = (_a = userConfig.allowedDisclosureHashAlgorithms) != null ? _a : DEFAULT_SECURE_HASH_ALGORITHMS;
1237
- if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) {
1238
- throw new SDJWTException(
1239
- `Disallowed hash algorithm: ${userConfig.hashAlg}`
1240
- );
1241
- }
1242
- this.userConfig = userConfig;
1243
- }
1244
- }
1245
- createKBJwt(options, sdHash) {
1246
- return __async(this, null, function* () {
1247
- if (!this.userConfig.kbSigner) {
1248
- throw new SDJWTException("Key Binding Signer not found");
1249
- }
1250
- if (!this.userConfig.kbSignAlg) {
1251
- throw new SDJWTException("Key Binding sign algorithm not specified");
1252
- }
1253
- const { payload } = options;
1254
- const kbJwt = new KBJwt({
1255
- header: {
1256
- typ: KB_JWT_TYP,
1257
- alg: this.userConfig.kbSignAlg
1258
- },
1259
- payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
1260
- });
1261
- yield kbJwt.sign(this.userConfig.kbSigner);
1262
- return kbJwt;
1263
- });
1264
- }
1265
- SignJwt(jwt) {
1266
- return __async(this, null, function* () {
1267
- if (!this.userConfig.signer) {
1268
- throw new SDJWTException("Signer not found");
1269
- }
1270
- yield jwt.sign(this.userConfig.signer);
1271
- return jwt;
1272
- });
1273
- }
1274
- VerifyJwt(jwt, options) {
1275
- return __async(this, null, function* () {
1276
- if (!this.userConfig.verifier) {
1277
- throw new SDJWTException("Verifier not found");
1278
- }
1279
- return jwt.verify(this.userConfig.verifier, options);
1280
- });
1281
- }
1282
- issue(payload, disclosureFrame, options) {
1283
- return __async(this, null, function* () {
1284
- var _a, _b, _c;
1285
- if (!this.userConfig.hasher) {
1286
- throw new SDJWTException("Hasher not found");
1287
- }
1288
- if (!this.userConfig.saltGenerator) {
1289
- throw new SDJWTException("SaltGenerator not found");
1290
- }
1291
- if (!this.userConfig.signAlg) {
1292
- throw new SDJWTException("sign alogrithm not specified");
1293
- }
1294
- if (this.userConfig.signAlg === "none") {
1295
- throw new SDJWTException('sign algorithm "none" is not allowed');
1296
- }
1297
- this.validateReservedFields(payload);
1298
- this.validateDisclosureFrame(disclosureFrame);
1299
- const hasher = this.userConfig.hasher;
1300
- const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
1301
- const allowedDisclosureHashAlgorithms = (_b = this.userConfig.allowedDisclosureHashAlgorithms) != null ? _b : DEFAULT_SECURE_HASH_ALGORITHMS;
1302
- if (!allowedDisclosureHashAlgorithms.includes(hashAlg)) {
1303
- throw new SDJWTException(`Disallowed hash algorithm: ${hashAlg}`);
1304
- }
1305
- const { packedClaims, disclosures } = yield pack(
1306
- payload,
1307
- disclosureFrame,
1308
- { hasher, alg: hashAlg },
1309
- this.userConfig.saltGenerator
1310
- );
1311
- const alg = this.userConfig.signAlg;
1312
- const OptionHeader = (_c = options == null ? void 0 : options.header) != null ? _c : {};
1313
- const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ: this.type }, OptionHeader);
1314
- const header = __spreadProps(__spreadValues({}, CustomHeader), { alg });
1315
- const jwt = new Jwt({
1316
- header,
1317
- payload: __spreadProps(__spreadValues({}, packedClaims), {
1318
- _sd_alg: disclosureFrame ? hashAlg : void 0
1319
- })
1320
- });
1321
- yield this.SignJwt(jwt);
1322
- const sdJwt = new SDJwt({
1323
- jwt,
1324
- disclosures
1325
- });
1326
- return sdJwt.encodeSDJwt();
1327
- });
1328
- }
1329
- /**
1330
- * Validates if the payload contains any reserved claim names. If so it will throw an error.
1331
- * @param payload
1332
- * @returns
1333
- */
1334
- validateReservedFields(payload) {
1335
- validateReservedFieldsInternal(payload);
1336
- }
1337
- validateDisclosureFrame(_disclosureFrame) {
1338
- return;
1339
- }
1340
- present(encodedSDJwt, presentationFrame, options) {
1341
- return __async(this, null, function* () {
1342
- var _a;
1343
- if (!this.userConfig.hasher) {
1344
- throw new SDJWTException("Hasher not found");
1345
- }
1346
- const hasher = this.userConfig.hasher;
1347
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1348
- if (sdjwt.kbJwt) {
1349
- throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1350
- }
1351
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
1352
- const presentSdJwtWithoutKb = yield sdjwt.present(
1353
- presentationFrame,
1354
- hasher
1355
- );
1356
- if (!(options == null ? void 0 : options.kb)) {
1357
- return presentSdJwtWithoutKb;
1358
- }
1359
- const sdHashStr = yield this.calculateSDHash(
1360
- presentSdJwtWithoutKb,
1361
- sdjwt,
1362
- hasher
1363
- );
1364
- sdjwt.kbJwt = yield this.createKBJwt(options.kb, sdHashStr);
1365
- return sdjwt.present(presentationFrame, hasher);
1366
- });
1367
- }
1368
- // This function is for verifying the SD JWT
1369
- // If requiredClaimKeys is provided, it will check if the required claim keys are presentation in the SD JWT
1370
- // If requireKeyBindings is true, it will check if the key binding JWT is presentation and verify it
1371
- verify(encodedSDJwt, options) {
1372
- return __async(this, null, function* () {
1373
- var _a;
1374
- if (!this.userConfig.hasher) {
1375
- throw new SDJWTException("Hasher not found");
1376
- }
1377
- const hasher = this.userConfig.hasher;
1378
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1379
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
1380
- throw new SDJWTException("Invalid SD JWT");
1381
- }
1382
- const { payload, header } = yield this.validate(encodedSDJwt, options);
1383
- if (options == null ? void 0 : options.requiredClaimKeys) {
1384
- const keys = yield sdjwt.keys(hasher);
1385
- const missingKeys = options.requiredClaimKeys.filter(
1386
- (k) => !keys.includes(k)
1387
- );
1388
- if (missingKeys.length > 0) {
1389
- throw new SDJWTException(
1390
- `Missing required claim keys: ${missingKeys.join(", ")}`
1391
- );
1392
- }
1393
- }
1394
- if (!(options == null ? void 0 : options.keyBindingNonce)) {
1395
- return { payload, header };
1396
- }
1397
- if (!sdjwt.kbJwt) {
1398
- throw new SDJWTException("Key Binding JWT not exist");
1399
- }
1400
- if (!this.userConfig.kbVerifier) {
1401
- throw new SDJWTException("Key Binding Verifier not found");
1402
- }
1403
- const kb = yield sdjwt.kbJwt.verifyKB({
1404
- verifier: this.userConfig.kbVerifier,
1405
- payload,
1406
- nonce: options.keyBindingNonce,
1407
- options
1408
- });
1409
- if (!kb) {
1410
- throw new Error("signature is not valid");
1411
- }
1412
- const sdHashfromKb = kb.payload.sd_hash;
1413
- const sdjwtWithoutKb = new SDJwt({
1414
- jwt: sdjwt.jwt,
1415
- disclosures: sdjwt.disclosures
1416
- });
1417
- const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
1418
- const sdHashStr = yield this.calculateSDHash(
1419
- presentSdJwtWithoutKb,
1420
- sdjwt,
1421
- hasher
1422
- );
1423
- if (sdHashStr !== sdHashfromKb) {
1424
- throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1425
- }
1426
- return { payload, header, kb };
1427
- });
1428
- }
1429
- /**
1430
- * Safe verification that collects all errors instead of failing fast.
1431
- * Returns a result object with either the verified data or an array of all errors.
1432
- *
1433
- * @param encodedSDJwt - The encoded SD-JWT to verify
1434
- * @param options - Verification options
1435
- * @returns A SafeVerifyResult containing either success data or collected errors
1436
- */
1437
- safeVerify(encodedSDJwt, options) {
1438
- return __async(this, null, function* () {
1439
- var _a;
1440
- const errors = [];
1441
- const addError = (code, message, details) => {
1442
- errors.push({ code, message, details });
1443
- };
1444
- const exceptionToCode = (error) => {
1445
- const message = error.message.toLowerCase();
1446
- if (message.includes("hasher not found")) return "HASHER_NOT_FOUND";
1447
- if (message.includes("verifier not found")) return "VERIFIER_NOT_FOUND";
1448
- if (message.includes("invalid sd jwt") || message.includes("invalid jwt"))
1449
- return "INVALID_SD_JWT";
1450
- if (message.includes("not yet valid")) return "JWT_NOT_YET_VALID";
1451
- if (message.includes("expired")) return "JWT_EXPIRED";
1452
- if (message.includes("signature")) return "INVALID_JWT_SIGNATURE";
1453
- if (message.includes("missing required claim"))
1454
- return "MISSING_REQUIRED_CLAIMS";
1455
- if (message.includes("key binding jwt not exist"))
1456
- return "KEY_BINDING_JWT_MISSING";
1457
- if (message.includes("key binding verifier not found"))
1458
- return "KEY_BINDING_VERIFIER_NOT_FOUND";
1459
- if (message.includes("sd_hash")) return "KEY_BINDING_SD_HASH_INVALID";
1460
- return "UNKNOWN_ERROR";
1461
- };
1462
- if (!this.userConfig.hasher) {
1463
- addError("HASHER_NOT_FOUND", "Hasher not found");
1464
- }
1465
- if (!this.userConfig.verifier) {
1466
- addError("VERIFIER_NOT_FOUND", "Verifier not found");
1467
- }
1468
- if (errors.length > 0) {
1469
- return { success: false, errors };
1470
- }
1471
- if (!this.userConfig.hasher) {
1472
- throw new SDJWTException("Hasher not found");
1473
- }
1474
- const hasher = this.userConfig.hasher;
1475
- let sdjwt;
1476
- let payload;
1477
- let header;
1478
- try {
1479
- sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1480
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
1481
- addError("INVALID_SD_JWT", "Invalid SD JWT: missing JWT or payload");
1482
- }
1483
- } catch (e) {
1484
- const error = ensureError(e);
1485
- addError(
1486
- "INVALID_SD_JWT",
1487
- `Failed to decode SD-JWT: ${error.message}`,
1488
- error
1489
- );
1490
- }
1491
- if (sdjwt == null ? void 0 : sdjwt.jwt) {
1492
- try {
1493
- const result = yield this.VerifyJwt(sdjwt.jwt, __spreadProps(__spreadValues({}, options), {
1494
- skipJwtClaimValidation: true
1495
- }));
1496
- header = result.header;
1497
- const claims = yield sdjwt.getClaims(hasher);
1498
- payload = claims;
1499
- validateJwtPayload(payload, options);
1500
- } catch (e) {
1501
- const error = ensureError(e);
1502
- const code = exceptionToCode(error);
1503
- addError(code, error.message, error);
1504
- }
1505
- }
1506
- if (sdjwt && (options == null ? void 0 : options.requiredClaimKeys)) {
1507
- try {
1508
- const keys = yield sdjwt.keys(hasher);
1509
- const missingKeys = options.requiredClaimKeys.filter(
1510
- (k) => !keys.includes(k)
1511
- );
1512
- if (missingKeys.length > 0) {
1513
- addError(
1514
- "MISSING_REQUIRED_CLAIMS",
1515
- `Missing required claim keys: ${missingKeys.join(", ")}`,
1516
- { missingKeys }
1517
- );
1518
- }
1519
- } catch (e) {
1520
- const error = ensureError(e);
1521
- addError(
1522
- "UNKNOWN_ERROR",
1523
- `Failed to check required claims: ${error.message}`,
1524
- error
1525
- );
1526
- }
1527
- }
1528
- let kb;
1529
- if ((options == null ? void 0 : options.keyBindingNonce) && sdjwt) {
1530
- if (!sdjwt.kbJwt) {
1531
- addError("KEY_BINDING_JWT_MISSING", "Key Binding JWT not exist");
1532
- } else if (!this.userConfig.kbVerifier) {
1533
- addError(
1534
- "KEY_BINDING_VERIFIER_NOT_FOUND",
1535
- "Key Binding Verifier not found"
1536
- );
1537
- } else if (payload) {
1538
- try {
1539
- const kbResult = yield sdjwt.kbJwt.verifyKB({
1540
- verifier: this.userConfig.kbVerifier,
1541
- payload,
1542
- nonce: options.keyBindingNonce,
1543
- options
1544
- });
1545
- if (!kbResult) {
1546
- addError(
1547
- "KEY_BINDING_SIGNATURE_INVALID",
1548
- "Key binding signature is not valid"
1549
- );
1550
- } else {
1551
- kb = kbResult;
1552
- const sdjwtWithoutKb = new SDJwt({
1553
- jwt: sdjwt.jwt,
1554
- disclosures: sdjwt.disclosures
1555
- });
1556
- const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
1557
- const sdHashStr = yield this.calculateSDHash(
1558
- presentSdJwtWithoutKb,
1559
- sdjwt,
1560
- hasher
1561
- );
1562
- if (sdHashStr !== kbResult.payload.sd_hash) {
1563
- addError(
1564
- "KEY_BINDING_SD_HASH_INVALID",
1565
- "Invalid sd_hash in Key Binding JWT",
1566
- {
1567
- expected: sdHashStr,
1568
- received: kbResult.payload.sd_hash
1569
- }
1570
- );
1571
- }
1572
- }
1573
- } catch (e) {
1574
- const error = ensureError(e);
1575
- addError(
1576
- "KEY_BINDING_SIGNATURE_INVALID",
1577
- `Key binding verification failed: ${error.message}`,
1578
- error
1579
- );
1580
- }
1581
- }
1582
- }
1583
- if (errors.length > 0) {
1584
- return { success: false, errors };
1585
- }
1586
- return {
1587
- success: true,
1588
- data: {
1589
- payload,
1590
- header,
1591
- kb
1592
- }
1593
- };
1594
- });
1595
- }
1596
- calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1597
- return __async(this, null, function* () {
1598
- var _a;
1599
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
1600
- throw new SDJWTException("Invalid SD JWT");
1601
- }
1602
- const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1603
- const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
1604
- const sdHashStr = uint8ArrayToBase64Url(sdHash);
1605
- return sdHashStr;
1606
- });
1607
- }
1608
- /**
1609
- * This function is for validating the SD JWT
1610
- * Checking signature, if provided the iat and exp when provided and return its the claims
1611
- * @param encodedSDJwt
1612
- * @param options
1613
- * @returns
1614
- */
1615
- validate(encodedSDJwt, options) {
1616
- return __async(this, null, function* () {
1617
- if (!this.userConfig.hasher) {
1618
- throw new SDJWTException("Hasher not found");
1619
- }
1620
- const hasher = this.userConfig.hasher;
1621
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1622
- if (!sdjwt.jwt) {
1623
- throw new SDJWTException("Invalid SD JWT");
1624
- }
1625
- const verifiedPayloads = yield this.VerifyJwt(sdjwt.jwt, __spreadProps(__spreadValues({}, options), {
1626
- skipJwtClaimValidation: true
1627
- }));
1628
- const claims = yield sdjwt.getClaims(hasher);
1629
- validateReservedFieldsInternal(claims);
1630
- validateJwtPayload(claims, options);
1631
- return { payload: claims, header: verifiedPayloads.header };
1632
- });
1633
- }
1634
- config(newConfig) {
1635
- this.userConfig = __spreadValues(__spreadValues({}, this.userConfig), newConfig);
1636
- }
1637
- encode(sdJwt) {
1638
- return sdJwt.encodeSDJwt();
1639
- }
1640
- decode(endcodedSDJwt) {
1641
- if (!this.userConfig.hasher) {
1642
- throw new SDJWTException("Hasher not found");
1643
- }
1644
- return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1645
- }
1646
- keys(endcodedSDJwt) {
1647
- return __async(this, null, function* () {
1648
- if (!this.userConfig.hasher) {
1649
- throw new SDJWTException("Hasher not found");
1650
- }
1651
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1652
- return sdjwt.keys(this.userConfig.hasher);
1653
- });
1654
- }
1655
- presentableKeys(endcodedSDJwt) {
1656
- return __async(this, null, function* () {
1657
- if (!this.userConfig.hasher) {
1658
- throw new SDJWTException("Hasher not found");
1659
- }
1660
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1661
- return sdjwt.presentableKeys(this.userConfig.hasher);
1662
- });
1663
- }
1664
- getClaims(endcodedSDJwt) {
1665
- return __async(this, null, function* () {
1666
- if (!this.userConfig.hasher) {
1667
- throw new SDJWTException("Hasher not found");
1668
- }
1669
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1670
- return sdjwt.getClaims(this.userConfig.hasher);
1671
- });
1672
- }
1673
- toFlattenJSON(endcodedSDJwt) {
1674
- return FlattenJSON.fromEncode(endcodedSDJwt);
1675
- }
1676
- toGeneralJSON(endcodedSDJwt) {
1677
- return GeneralJSON.fromEncode(endcodedSDJwt);
1678
- }
956
+ var SDJwtInstance = class SDJwtInstance {
957
+ static {
958
+ this.DEFAULT_hashAlg = "sha-256";
959
+ }
960
+ constructor(userConfig) {
961
+ this.userConfig = {};
962
+ if (userConfig) {
963
+ if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) throw new SDJWTException(`Invalid hash algorithm: ${userConfig.hashAlg}`);
964
+ const allowedDisclosureHashAlgorithms = userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS;
965
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${userConfig.hashAlg}`);
966
+ this.userConfig = userConfig;
967
+ }
968
+ }
969
+ async createKBJwt(options, sdHash) {
970
+ if (!this.userConfig.kbSigner) throw new SDJWTException("Key Binding Signer not found");
971
+ if (!this.userConfig.kbSignAlg) throw new SDJWTException("Key Binding sign algorithm not specified");
972
+ const { payload } = options;
973
+ const kbJwt = new KBJwt({
974
+ header: {
975
+ typ: KB_JWT_TYP,
976
+ alg: this.userConfig.kbSignAlg
977
+ },
978
+ payload: {
979
+ ...payload,
980
+ sd_hash: sdHash
981
+ }
982
+ });
983
+ await kbJwt.sign(this.userConfig.kbSigner);
984
+ return kbJwt;
985
+ }
986
+ async SignJwt(jwt) {
987
+ if (!this.userConfig.signer) throw new SDJWTException("Signer not found");
988
+ await jwt.sign(this.userConfig.signer);
989
+ return jwt;
990
+ }
991
+ async VerifyJwt(jwt, options) {
992
+ if (!this.userConfig.verifier) throw new SDJWTException("Verifier not found");
993
+ return jwt.verify(this.userConfig.verifier, options);
994
+ }
995
+ async issue(payload, disclosureFrame, options) {
996
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
997
+ if (!this.userConfig.saltGenerator) throw new SDJWTException("SaltGenerator not found");
998
+ if (!this.userConfig.signAlg) throw new SDJWTException("sign alogrithm not specified");
999
+ if (this.userConfig.signAlg === "none") throw new SDJWTException("sign algorithm \"none\" is not allowed");
1000
+ this.validateReservedFields(payload);
1001
+ this.validateDisclosureFrame(disclosureFrame);
1002
+ const hasher = this.userConfig.hasher;
1003
+ const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
1004
+ if (!(this.userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS).includes(hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${hashAlg}`);
1005
+ const { packedClaims, disclosures } = await pack(payload, disclosureFrame, {
1006
+ hasher,
1007
+ alg: hashAlg
1008
+ }, this.userConfig.saltGenerator);
1009
+ const alg = this.userConfig.signAlg;
1010
+ const OptionHeader = options?.header ?? {};
1011
+ const jwt = new Jwt({
1012
+ header: {
1013
+ ...this.userConfig.omitTyp ? OptionHeader : {
1014
+ typ: this.type,
1015
+ ...OptionHeader
1016
+ },
1017
+ alg
1018
+ },
1019
+ payload: {
1020
+ ...packedClaims,
1021
+ _sd_alg: disclosureFrame ? hashAlg : void 0
1022
+ }
1023
+ });
1024
+ await this.SignJwt(jwt);
1025
+ return new SDJwt({
1026
+ jwt,
1027
+ disclosures
1028
+ }).encodeSDJwt();
1029
+ }
1030
+ /**
1031
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1032
+ * @param payload
1033
+ * @returns
1034
+ */
1035
+ validateReservedFields(payload) {
1036
+ validateReservedFieldsInternal(payload);
1037
+ }
1038
+ validateDisclosureFrame(_disclosureFrame) {}
1039
+ async present(encodedSDJwt, presentationFrame, options) {
1040
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1041
+ const hasher = this.userConfig.hasher;
1042
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1043
+ if (sdjwt.kbJwt) throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1044
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Payload not found");
1045
+ const presentSdJwtWithoutKb = await sdjwt.present(presentationFrame, hasher);
1046
+ if (!options?.kb) return presentSdJwtWithoutKb;
1047
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1048
+ sdjwt.kbJwt = await this.createKBJwt(options.kb, sdHashStr);
1049
+ return sdjwt.present(presentationFrame, hasher);
1050
+ }
1051
+ async verify(encodedSDJwt, options) {
1052
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1053
+ const hasher = this.userConfig.hasher;
1054
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1055
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1056
+ const { payload, header } = await this.validate(encodedSDJwt, options);
1057
+ if (options?.requiredClaimKeys) {
1058
+ const keys = await sdjwt.keys(hasher);
1059
+ const missingKeys = options.requiredClaimKeys.filter((k) => !keys.includes(k));
1060
+ if (missingKeys.length > 0) throw new SDJWTException(`Missing required claim keys: ${missingKeys.join(", ")}`);
1061
+ }
1062
+ if (!options?.keyBindingNonce) return {
1063
+ payload,
1064
+ header
1065
+ };
1066
+ if (!sdjwt.kbJwt) throw new SDJWTException("Key Binding JWT not exist");
1067
+ if (!this.userConfig.kbVerifier) throw new SDJWTException("Key Binding Verifier not found");
1068
+ const kb = await sdjwt.kbJwt.verifyKB({
1069
+ verifier: this.userConfig.kbVerifier,
1070
+ payload,
1071
+ nonce: options.keyBindingNonce,
1072
+ options
1073
+ });
1074
+ if (!kb) throw new Error("signature is not valid");
1075
+ const sdHashfromKb = kb.payload.sd_hash;
1076
+ const presentSdJwtWithoutKb = new SDJwt({
1077
+ jwt: sdjwt.jwt,
1078
+ disclosures: sdjwt.disclosures
1079
+ }).encodeSDJwt();
1080
+ if (await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) !== sdHashfromKb) throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1081
+ return {
1082
+ payload,
1083
+ header,
1084
+ kb
1085
+ };
1086
+ }
1087
+ /**
1088
+ * Safe verification that collects all errors instead of failing fast.
1089
+ * Returns a result object with either the verified data or an array of all errors.
1090
+ *
1091
+ * @param encodedSDJwt - The encoded SD-JWT to verify
1092
+ * @param options - Verification options
1093
+ * @returns A SafeVerifyResult containing either success data or collected errors
1094
+ */
1095
+ async safeVerify(encodedSDJwt, options) {
1096
+ const errors = [];
1097
+ const addError = (code, message, details) => {
1098
+ errors.push({
1099
+ code,
1100
+ message,
1101
+ details
1102
+ });
1103
+ };
1104
+ const exceptionToCode = (error) => {
1105
+ const message = error.message.toLowerCase();
1106
+ if (message.includes("hasher not found")) return "HASHER_NOT_FOUND";
1107
+ if (message.includes("verifier not found")) return "VERIFIER_NOT_FOUND";
1108
+ if (message.includes("invalid sd jwt") || message.includes("invalid jwt")) return "INVALID_SD_JWT";
1109
+ if (message.includes("not yet valid")) return "JWT_NOT_YET_VALID";
1110
+ if (message.includes("expired")) return "JWT_EXPIRED";
1111
+ if (message.includes("signature")) return "INVALID_JWT_SIGNATURE";
1112
+ if (message.includes("missing required claim")) return "MISSING_REQUIRED_CLAIMS";
1113
+ if (message.includes("key binding jwt not exist")) return "KEY_BINDING_JWT_MISSING";
1114
+ if (message.includes("key binding verifier not found")) return "KEY_BINDING_VERIFIER_NOT_FOUND";
1115
+ if (message.includes("sd_hash")) return "KEY_BINDING_SD_HASH_INVALID";
1116
+ return "UNKNOWN_ERROR";
1117
+ };
1118
+ if (!this.userConfig.hasher) addError("HASHER_NOT_FOUND", "Hasher not found");
1119
+ if (!this.userConfig.verifier) addError("VERIFIER_NOT_FOUND", "Verifier not found");
1120
+ if (errors.length > 0) return {
1121
+ success: false,
1122
+ errors
1123
+ };
1124
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1125
+ const hasher = this.userConfig.hasher;
1126
+ let sdjwt;
1127
+ let payload;
1128
+ let header;
1129
+ try {
1130
+ sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1131
+ if (!sdjwt.jwt?.payload) addError("INVALID_SD_JWT", "Invalid SD JWT: missing JWT or payload");
1132
+ } catch (e) {
1133
+ const error = ensureError(e);
1134
+ addError("INVALID_SD_JWT", `Failed to decode SD-JWT: ${error.message}`, error);
1135
+ }
1136
+ if (sdjwt?.jwt) try {
1137
+ header = (await this.VerifyJwt(sdjwt.jwt, {
1138
+ ...options,
1139
+ skipJwtClaimValidation: true
1140
+ })).header;
1141
+ payload = await sdjwt.getClaims(hasher);
1142
+ validateJwtPayload(payload, options);
1143
+ } catch (e) {
1144
+ const error = ensureError(e);
1145
+ addError(exceptionToCode(error), error.message, error);
1146
+ }
1147
+ if (sdjwt && options?.requiredClaimKeys) try {
1148
+ const keys = await sdjwt.keys(hasher);
1149
+ const missingKeys = options.requiredClaimKeys.filter((k) => !keys.includes(k));
1150
+ if (missingKeys.length > 0) addError("MISSING_REQUIRED_CLAIMS", `Missing required claim keys: ${missingKeys.join(", ")}`, { missingKeys });
1151
+ } catch (e) {
1152
+ const error = ensureError(e);
1153
+ addError("UNKNOWN_ERROR", `Failed to check required claims: ${error.message}`, error);
1154
+ }
1155
+ let kb;
1156
+ if (options?.keyBindingNonce && sdjwt) {
1157
+ if (!sdjwt.kbJwt) addError("KEY_BINDING_JWT_MISSING", "Key Binding JWT not exist");
1158
+ else if (!this.userConfig.kbVerifier) addError("KEY_BINDING_VERIFIER_NOT_FOUND", "Key Binding Verifier not found");
1159
+ else if (payload) try {
1160
+ const kbResult = await sdjwt.kbJwt.verifyKB({
1161
+ verifier: this.userConfig.kbVerifier,
1162
+ payload,
1163
+ nonce: options.keyBindingNonce,
1164
+ options
1165
+ });
1166
+ if (!kbResult) addError("KEY_BINDING_SIGNATURE_INVALID", "Key binding signature is not valid");
1167
+ else {
1168
+ kb = kbResult;
1169
+ const presentSdJwtWithoutKb = new SDJwt({
1170
+ jwt: sdjwt.jwt,
1171
+ disclosures: sdjwt.disclosures
1172
+ }).encodeSDJwt();
1173
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1174
+ if (sdHashStr !== kbResult.payload.sd_hash) addError("KEY_BINDING_SD_HASH_INVALID", "Invalid sd_hash in Key Binding JWT", {
1175
+ expected: sdHashStr,
1176
+ received: kbResult.payload.sd_hash
1177
+ });
1178
+ }
1179
+ } catch (e) {
1180
+ const error = ensureError(e);
1181
+ addError("KEY_BINDING_SIGNATURE_INVALID", `Key binding verification failed: ${error.message}`, error);
1182
+ }
1183
+ }
1184
+ if (errors.length > 0) return {
1185
+ success: false,
1186
+ errors
1187
+ };
1188
+ return {
1189
+ success: true,
1190
+ data: {
1191
+ payload,
1192
+ header,
1193
+ kb
1194
+ }
1195
+ };
1196
+ }
1197
+ async calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1198
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1199
+ const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1200
+ const sdHash = await hasher(presentSdJwtWithoutKb, _sd_alg);
1201
+ return uint8ArrayToBase64Url(sdHash);
1202
+ }
1203
+ /**
1204
+ * This function is for validating the SD JWT
1205
+ * Checking signature, if provided the iat and exp when provided and return its the claims
1206
+ * @param encodedSDJwt
1207
+ * @param options
1208
+ * @returns
1209
+ */
1210
+ async validate(encodedSDJwt, options) {
1211
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1212
+ const hasher = this.userConfig.hasher;
1213
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1214
+ if (!sdjwt.jwt) throw new SDJWTException("Invalid SD JWT");
1215
+ const verifiedPayloads = await this.VerifyJwt(sdjwt.jwt, {
1216
+ ...options,
1217
+ skipJwtClaimValidation: true
1218
+ });
1219
+ const claims = await sdjwt.getClaims(hasher);
1220
+ validateReservedFieldsInternal(claims);
1221
+ validateJwtPayload(claims, options);
1222
+ return {
1223
+ payload: claims,
1224
+ header: verifiedPayloads.header
1225
+ };
1226
+ }
1227
+ config(newConfig) {
1228
+ this.userConfig = {
1229
+ ...this.userConfig,
1230
+ ...newConfig
1231
+ };
1232
+ }
1233
+ encode(sdJwt) {
1234
+ return sdJwt.encodeSDJwt();
1235
+ }
1236
+ decode(endcodedSDJwt) {
1237
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1238
+ return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1239
+ }
1240
+ async keys(endcodedSDJwt) {
1241
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1242
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).keys(this.userConfig.hasher);
1243
+ }
1244
+ async presentableKeys(endcodedSDJwt) {
1245
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1246
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).presentableKeys(this.userConfig.hasher);
1247
+ }
1248
+ async getClaims(endcodedSDJwt) {
1249
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1250
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).getClaims(this.userConfig.hasher);
1251
+ }
1252
+ toFlattenJSON(endcodedSDJwt) {
1253
+ return FlattenJSON.fromEncode(endcodedSDJwt);
1254
+ }
1255
+ toGeneralJSON(endcodedSDJwt) {
1256
+ return GeneralJSON.fromEncode(endcodedSDJwt);
1257
+ }
1679
1258
  };
1680
- _SDJwtInstance.DEFAULT_hashAlg = "sha-256";
1681
- var SDJwtInstance = _SDJwtInstance;
1682
1259
  var SDJwtGeneralJSONInstance = class {
1683
- constructor(userConfig) {
1684
- this.userConfig = {};
1685
- var _a;
1686
- if (userConfig) {
1687
- if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
1688
- throw new SDJWTException(
1689
- `Invalid hash algorithm: ${userConfig.hashAlg}`
1690
- );
1691
- }
1692
- const allowedDisclosureHashAlgorithms = (_a = userConfig.allowedDisclosureHashAlgorithms) != null ? _a : DEFAULT_SECURE_HASH_ALGORITHMS;
1693
- if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) {
1694
- throw new SDJWTException(
1695
- `Disallowed hash algorithm: ${userConfig.hashAlg}`
1696
- );
1697
- }
1698
- this.userConfig = userConfig;
1699
- }
1700
- }
1701
- createKBJwt(options, sdHash) {
1702
- return __async(this, null, function* () {
1703
- if (!this.userConfig.kbSigner) {
1704
- throw new SDJWTException("Key Binding Signer not found");
1705
- }
1706
- if (!this.userConfig.kbSignAlg) {
1707
- throw new SDJWTException("Key Binding sign algorithm not specified");
1708
- }
1709
- const { payload } = options;
1710
- const kbJwt = new KBJwt({
1711
- header: {
1712
- typ: KB_JWT_TYP,
1713
- alg: this.userConfig.kbSignAlg
1714
- },
1715
- payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
1716
- });
1717
- yield kbJwt.sign(this.userConfig.kbSigner);
1718
- return kbJwt;
1719
- });
1720
- }
1721
- encodeObj(obj) {
1722
- return base64urlEncode(JSON.stringify(obj));
1723
- }
1724
- issue(payload, disclosureFrame, options) {
1725
- return __async(this, null, function* () {
1726
- var _a;
1727
- if (!this.userConfig.hasher) {
1728
- throw new SDJWTException("Hasher not found");
1729
- }
1730
- if (!this.userConfig.saltGenerator) {
1731
- throw new SDJWTException("SaltGenerator not found");
1732
- }
1733
- this.validateReservedFields(payload);
1734
- this.validateDisclosureFrame(disclosureFrame);
1735
- const hasher = this.userConfig.hasher;
1736
- const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : SDJwtInstance.DEFAULT_hashAlg;
1737
- const { packedClaims, disclosures } = yield pack(
1738
- payload,
1739
- disclosureFrame,
1740
- { hasher, alg: hashAlg },
1741
- this.userConfig.saltGenerator
1742
- );
1743
- const encodedSDJwtPayload = this.encodeObj(__spreadProps(__spreadValues({}, packedClaims), {
1744
- _sd_alg: disclosureFrame ? hashAlg : void 0
1745
- }));
1746
- const encodedDisclosures = disclosures.map(
1747
- (disclosure) => disclosure.encode()
1748
- );
1749
- const signatures = yield Promise.all(
1750
- options.sigs.map((s) => __async(this, null, function* () {
1751
- const { signer, alg, kid, header } = s;
1752
- const protectedHeader = __spreadValues({ typ: this.type, alg, kid }, header);
1753
- const encodedProtectedHeader = this.encodeObj(protectedHeader);
1754
- const signature = yield signer(
1755
- `${encodedProtectedHeader}.${encodedSDJwtPayload}`
1756
- );
1757
- return {
1758
- protected: encodedProtectedHeader,
1759
- signature
1760
- };
1761
- }))
1762
- );
1763
- const generalJson = new GeneralJSON({
1764
- payload: encodedSDJwtPayload,
1765
- disclosures: encodedDisclosures,
1766
- signatures
1767
- });
1768
- return generalJson;
1769
- });
1770
- }
1771
- /**
1772
- * Validates if the payload contains any reserved claim names. If so it will throw an error.
1773
- * @param payload
1774
- * @returns
1775
- */
1776
- validateReservedFields(payload) {
1777
- validateReservedFieldsInternal(payload);
1778
- }
1779
- validateDisclosureFrame(_disclosureFrame) {
1780
- return;
1781
- }
1782
- present(generalJSON, presentationFrame, options) {
1783
- return __async(this, null, function* () {
1784
- var _a;
1785
- if (!this.userConfig.hasher) {
1786
- throw new SDJWTException("Hasher not found");
1787
- }
1788
- const hasher = this.userConfig.hasher;
1789
- const encodedSDJwt = generalJSON.toEncoded(0);
1790
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1791
- if (sdjwt.kbJwt) {
1792
- throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1793
- }
1794
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
1795
- const disclosures = yield sdjwt.getPresentDisclosures(
1796
- presentationFrame,
1797
- hasher
1798
- );
1799
- const encodedDisclosures = disclosures.map((d) => d.encode());
1800
- const presentedGeneralJSON = new GeneralJSON({
1801
- payload: generalJSON.payload,
1802
- disclosures: encodedDisclosures,
1803
- signatures: generalJSON.signatures
1804
- });
1805
- if (!(options == null ? void 0 : options.kb)) {
1806
- return presentedGeneralJSON;
1807
- }
1808
- const presentSdJwtWithoutKb = yield sdjwt.present(
1809
- presentationFrame,
1810
- hasher
1811
- );
1812
- const sdHashStr = yield this.calculateSDHash(
1813
- presentSdJwtWithoutKb,
1814
- sdjwt,
1815
- hasher
1816
- );
1817
- const kbJwt = yield this.createKBJwt(options.kb, sdHashStr);
1818
- const encodedKbJwt = kbJwt.encodeJwt();
1819
- presentedGeneralJSON.kb_jwt = encodedKbJwt;
1820
- return presentedGeneralJSON;
1821
- });
1822
- }
1823
- // This function is for verifying the SD JWT
1824
- // If requiredClaimKeys is provided, it will check if the required claim keys are presentation in the SD JWT
1825
- // If requireKeyBindings is true, it will check if the key binding JWT is presentation and verify it
1826
- verify(generalJSON, options) {
1827
- return __async(this, null, function* () {
1828
- var _a;
1829
- if (!this.userConfig.hasher) {
1830
- throw new SDJWTException("Hasher not found");
1831
- }
1832
- const hasher = this.userConfig.hasher;
1833
- const { payload, headers } = yield this.validate(generalJSON, options);
1834
- const encodedSDJwt = generalJSON.toEncoded(0);
1835
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1836
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
1837
- throw new SDJWTException("Invalid SD JWT");
1838
- }
1839
- if (options == null ? void 0 : options.requiredClaimKeys) {
1840
- const keys = yield sdjwt.keys(hasher);
1841
- const missingKeys = options == null ? void 0 : options.requiredClaimKeys.filter(
1842
- (k) => !keys.includes(k)
1843
- );
1844
- if (missingKeys.length > 0) {
1845
- throw new SDJWTException(
1846
- `Missing required claim keys: ${missingKeys.join(", ")}`
1847
- );
1848
- }
1849
- }
1850
- if (!(options == null ? void 0 : options.keyBindingNonce)) {
1851
- return { payload, headers };
1852
- }
1853
- if (!sdjwt.kbJwt) {
1854
- throw new SDJWTException("Key Binding JWT not exist");
1855
- }
1856
- if (!this.userConfig.kbVerifier) {
1857
- throw new SDJWTException("Key Binding Verifier not found");
1858
- }
1859
- const kb = yield sdjwt.kbJwt.verifyKB({
1860
- verifier: this.userConfig.kbVerifier,
1861
- payload,
1862
- nonce: options.keyBindingNonce,
1863
- options
1864
- });
1865
- if (!kb) {
1866
- throw new Error("signature is not valid");
1867
- }
1868
- const sdHashfromKb = kb.payload.sd_hash;
1869
- const sdjwtWithoutKb = new SDJwt({
1870
- jwt: sdjwt.jwt,
1871
- disclosures: sdjwt.disclosures
1872
- });
1873
- const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
1874
- const sdHashStr = yield this.calculateSDHash(
1875
- presentSdJwtWithoutKb,
1876
- sdjwt,
1877
- hasher
1878
- );
1879
- if (sdHashStr !== sdHashfromKb) {
1880
- throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1881
- }
1882
- return { payload, headers, kb };
1883
- });
1884
- }
1885
- calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1886
- return __async(this, null, function* () {
1887
- var _a;
1888
- if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
1889
- throw new SDJWTException("Invalid SD JWT");
1890
- }
1891
- const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1892
- const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
1893
- const sdHashStr = uint8ArrayToBase64Url(sdHash);
1894
- return sdHashStr;
1895
- });
1896
- }
1897
- // This function is for validating the SD JWT
1898
- // Just checking signature and return its the claims
1899
- validate(generalJSON, options) {
1900
- return __async(this, null, function* () {
1901
- if (!this.userConfig.hasher) {
1902
- throw new SDJWTException("Hasher not found");
1903
- }
1904
- if (!this.userConfig.verifier) {
1905
- throw new SDJWTException("Verifier not found");
1906
- }
1907
- const hasher = this.userConfig.hasher;
1908
- const verifier = this.userConfig.verifier;
1909
- const { payload, signatures } = generalJSON;
1910
- const results = yield Promise.all(
1911
- signatures.map((s) => __async(this, null, function* () {
1912
- const { protected: encodedHeader, signature } = s;
1913
- const verified2 = yield verifier(
1914
- `${encodedHeader}.${payload}`,
1915
- signature,
1916
- __spreadProps(__spreadValues({}, options), { skipJwtClaimValidation: true })
1917
- );
1918
- const header = decodeBase64urlJsonStrict(
1919
- encodedHeader,
1920
- "Invalid JWT"
1921
- );
1922
- if (typeof header.alg !== "string" || header.alg === "none") {
1923
- throw new SDJWTException('Verify Error: alg "none" is not allowed');
1924
- }
1925
- if ((options == null ? void 0 : options.allowedIssuerAlgorithms) && !options.allowedIssuerAlgorithms.includes(header.alg)) {
1926
- throw new SDJWTException(
1927
- `Verify Error: Disallowed alg ${header.alg}`
1928
- );
1929
- }
1930
- return { verified: verified2, header };
1931
- }))
1932
- );
1933
- const verified = results.every((r) => r.verified);
1934
- if (!verified) {
1935
- throw new SDJWTException("Signature is not valid");
1936
- }
1937
- const encodedSDJwt = generalJSON.toEncoded(0);
1938
- const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1939
- if (!sdjwt.jwt) {
1940
- throw new SDJWTException("Invalid SD JWT");
1941
- }
1942
- const claims = yield sdjwt.getClaims(hasher);
1943
- validateReservedFieldsInternal(claims);
1944
- validateJwtPayload(claims, options);
1945
- return { payload: claims, headers: results.map((r) => r.header) };
1946
- });
1947
- }
1948
- config(newConfig) {
1949
- this.userConfig = __spreadValues(__spreadValues({}, this.userConfig), newConfig);
1950
- }
1951
- encode(sdJwt, index) {
1952
- return sdJwt.toEncoded(index);
1953
- }
1954
- decode(endcodedSDJwt) {
1955
- return GeneralJSON.fromEncode(endcodedSDJwt);
1956
- }
1957
- keys(generalSdjwt) {
1958
- return __async(this, null, function* () {
1959
- if (!this.userConfig.hasher) {
1960
- throw new SDJWTException("Hasher not found");
1961
- }
1962
- const endcodedSDJwt = generalSdjwt.toEncoded(0);
1963
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1964
- return sdjwt.keys(this.userConfig.hasher);
1965
- });
1966
- }
1967
- presentableKeys(generalSdjwt) {
1968
- return __async(this, null, function* () {
1969
- if (!this.userConfig.hasher) {
1970
- throw new SDJWTException("Hasher not found");
1971
- }
1972
- const endcodedSDJwt = generalSdjwt.toEncoded(0);
1973
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1974
- return sdjwt.presentableKeys(this.userConfig.hasher);
1975
- });
1976
- }
1977
- getClaims(generalSdjwt) {
1978
- return __async(this, null, function* () {
1979
- if (!this.userConfig.hasher) {
1980
- throw new SDJWTException("Hasher not found");
1981
- }
1982
- const endcodedSDJwt = generalSdjwt.toEncoded(0);
1983
- const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1984
- return sdjwt.getClaims(this.userConfig.hasher);
1985
- });
1986
- }
1987
- };
1988
- SDJwtGeneralJSONInstance.DEFAULT_hashAlg = "sha-256";
1989
- export {
1990
- DEFAULT_SECURE_HASH_ALGORITHMS,
1991
- Disclosure,
1992
- FlattenJSON,
1993
- GeneralJSON,
1994
- IANA_HASH_ALGORITHMS,
1995
- Jwt,
1996
- KBJwt,
1997
- KB_JWT_TYP,
1998
- SDJWTException,
1999
- SDJwt,
2000
- SDJwtGeneralJSONInstance,
2001
- SDJwtInstance,
2002
- SD_DECOY,
2003
- SD_DIGEST,
2004
- SD_LIST_KEY,
2005
- SD_SEPARATOR,
2006
- base64UrlToUint8Array,
2007
- base64urlDecode,
2008
- base64urlEncode,
2009
- createDecoy,
2010
- createHashMapping,
2011
- createHashMappingForSerializedDisclosure,
2012
- createHashMappingSync,
2013
- decodeJwt,
2014
- decodeSdJwt,
2015
- decodeSdJwtSync,
2016
- encodePath,
2017
- encodePathSegment,
2018
- ensureError,
2019
- getClaims,
2020
- getClaimsSync,
2021
- getSDAlgAndPayload,
2022
- listKeys,
2023
- pack,
2024
- present,
2025
- presentSync,
2026
- presentableKeys,
2027
- presentableKeysSync,
2028
- selectDisclosures,
2029
- splitSdJwt,
2030
- transformPresentationFrame,
2031
- uint8ArrayToBase64Url,
2032
- unpack,
2033
- unpackObj,
2034
- unpackSync,
2035
- validateJwtPayload
1260
+ static {
1261
+ this.DEFAULT_hashAlg = "sha-256";
1262
+ }
1263
+ constructor(userConfig) {
1264
+ this.userConfig = {};
1265
+ if (userConfig) {
1266
+ if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) throw new SDJWTException(`Invalid hash algorithm: ${userConfig.hashAlg}`);
1267
+ const allowedDisclosureHashAlgorithms = userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS;
1268
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${userConfig.hashAlg}`);
1269
+ this.userConfig = userConfig;
1270
+ }
1271
+ }
1272
+ async createKBJwt(options, sdHash) {
1273
+ if (!this.userConfig.kbSigner) throw new SDJWTException("Key Binding Signer not found");
1274
+ if (!this.userConfig.kbSignAlg) throw new SDJWTException("Key Binding sign algorithm not specified");
1275
+ const { payload } = options;
1276
+ const kbJwt = new KBJwt({
1277
+ header: {
1278
+ typ: KB_JWT_TYP,
1279
+ alg: this.userConfig.kbSignAlg
1280
+ },
1281
+ payload: {
1282
+ ...payload,
1283
+ sd_hash: sdHash
1284
+ }
1285
+ });
1286
+ await kbJwt.sign(this.userConfig.kbSigner);
1287
+ return kbJwt;
1288
+ }
1289
+ encodeObj(obj) {
1290
+ return base64urlEncode(JSON.stringify(obj));
1291
+ }
1292
+ async issue(payload, disclosureFrame, options) {
1293
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1294
+ if (!this.userConfig.saltGenerator) throw new SDJWTException("SaltGenerator not found");
1295
+ this.validateReservedFields(payload);
1296
+ this.validateDisclosureFrame(disclosureFrame);
1297
+ const hasher = this.userConfig.hasher;
1298
+ const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
1299
+ const { packedClaims, disclosures } = await pack(payload, disclosureFrame, {
1300
+ hasher,
1301
+ alg: hashAlg
1302
+ }, this.userConfig.saltGenerator);
1303
+ const encodedSDJwtPayload = this.encodeObj({
1304
+ ...packedClaims,
1305
+ _sd_alg: disclosureFrame ? hashAlg : void 0
1306
+ });
1307
+ return new GeneralJSON({
1308
+ payload: encodedSDJwtPayload,
1309
+ disclosures: disclosures.map((disclosure) => disclosure.encode()),
1310
+ signatures: await Promise.all(options.sigs.map(async (s) => {
1311
+ const { signer, alg, kid, header } = s;
1312
+ const protectedHeader = {
1313
+ typ: this.type,
1314
+ alg,
1315
+ kid,
1316
+ ...header
1317
+ };
1318
+ const encodedProtectedHeader = this.encodeObj(protectedHeader);
1319
+ return {
1320
+ protected: encodedProtectedHeader,
1321
+ signature: await signer(`${encodedProtectedHeader}.${encodedSDJwtPayload}`)
1322
+ };
1323
+ }))
1324
+ });
1325
+ }
1326
+ /**
1327
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1328
+ * @param payload
1329
+ * @returns
1330
+ */
1331
+ validateReservedFields(payload) {
1332
+ validateReservedFieldsInternal(payload);
1333
+ }
1334
+ validateDisclosureFrame(_disclosureFrame) {}
1335
+ async present(generalJSON, presentationFrame, options) {
1336
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1337
+ const hasher = this.userConfig.hasher;
1338
+ const encodedSDJwt = generalJSON.toEncoded(0);
1339
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1340
+ if (sdjwt.kbJwt) throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1341
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Payload not found");
1342
+ const encodedDisclosures = (await sdjwt.getPresentDisclosures(presentationFrame, hasher)).map((d) => d.encode());
1343
+ const presentedGeneralJSON = new GeneralJSON({
1344
+ payload: generalJSON.payload,
1345
+ disclosures: encodedDisclosures,
1346
+ signatures: generalJSON.signatures
1347
+ });
1348
+ if (!options?.kb) return presentedGeneralJSON;
1349
+ const presentSdJwtWithoutKb = await sdjwt.present(presentationFrame, hasher);
1350
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1351
+ presentedGeneralJSON.kb_jwt = (await this.createKBJwt(options.kb, sdHashStr)).encodeJwt();
1352
+ return presentedGeneralJSON;
1353
+ }
1354
+ async verify(generalJSON, options) {
1355
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1356
+ const hasher = this.userConfig.hasher;
1357
+ const { payload, headers } = await this.validate(generalJSON, options);
1358
+ const encodedSDJwt = generalJSON.toEncoded(0);
1359
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1360
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1361
+ if (options?.requiredClaimKeys) {
1362
+ const keys = await sdjwt.keys(hasher);
1363
+ const missingKeys = options?.requiredClaimKeys.filter((k) => !keys.includes(k));
1364
+ if (missingKeys.length > 0) throw new SDJWTException(`Missing required claim keys: ${missingKeys.join(", ")}`);
1365
+ }
1366
+ if (!options?.keyBindingNonce) return {
1367
+ payload,
1368
+ headers
1369
+ };
1370
+ if (!sdjwt.kbJwt) throw new SDJWTException("Key Binding JWT not exist");
1371
+ if (!this.userConfig.kbVerifier) throw new SDJWTException("Key Binding Verifier not found");
1372
+ const kb = await sdjwt.kbJwt.verifyKB({
1373
+ verifier: this.userConfig.kbVerifier,
1374
+ payload,
1375
+ nonce: options.keyBindingNonce,
1376
+ options
1377
+ });
1378
+ if (!kb) throw new Error("signature is not valid");
1379
+ const sdHashfromKb = kb.payload.sd_hash;
1380
+ const presentSdJwtWithoutKb = new SDJwt({
1381
+ jwt: sdjwt.jwt,
1382
+ disclosures: sdjwt.disclosures
1383
+ }).encodeSDJwt();
1384
+ if (await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) !== sdHashfromKb) throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1385
+ return {
1386
+ payload,
1387
+ headers,
1388
+ kb
1389
+ };
1390
+ }
1391
+ async calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1392
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1393
+ const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1394
+ const sdHash = await hasher(presentSdJwtWithoutKb, _sd_alg);
1395
+ return uint8ArrayToBase64Url(sdHash);
1396
+ }
1397
+ async validate(generalJSON, options) {
1398
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1399
+ if (!this.userConfig.verifier) throw new SDJWTException("Verifier not found");
1400
+ const hasher = this.userConfig.hasher;
1401
+ const verifier = this.userConfig.verifier;
1402
+ const { payload, signatures } = generalJSON;
1403
+ const results = await Promise.all(signatures.map(async (s) => {
1404
+ const { protected: encodedHeader, signature } = s;
1405
+ const verified = await verifier(`${encodedHeader}.${payload}`, signature, {
1406
+ ...options,
1407
+ skipJwtClaimValidation: true
1408
+ });
1409
+ const header = decodeBase64urlJsonStrict(encodedHeader, "Invalid JWT");
1410
+ if (typeof header.alg !== "string" || header.alg === "none") throw new SDJWTException("Verify Error: alg \"none\" is not allowed");
1411
+ if (options?.allowedIssuerAlgorithms && !options.allowedIssuerAlgorithms.includes(header.alg)) throw new SDJWTException(`Verify Error: Disallowed alg ${header.alg}`);
1412
+ return {
1413
+ verified,
1414
+ header
1415
+ };
1416
+ }));
1417
+ if (!results.every((r) => r.verified)) throw new SDJWTException("Signature is not valid");
1418
+ const encodedSDJwt = generalJSON.toEncoded(0);
1419
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1420
+ if (!sdjwt.jwt) throw new SDJWTException("Invalid SD JWT");
1421
+ const claims = await sdjwt.getClaims(hasher);
1422
+ validateReservedFieldsInternal(claims);
1423
+ validateJwtPayload(claims, options);
1424
+ return {
1425
+ payload: claims,
1426
+ headers: results.map((r) => r.header)
1427
+ };
1428
+ }
1429
+ config(newConfig) {
1430
+ this.userConfig = {
1431
+ ...this.userConfig,
1432
+ ...newConfig
1433
+ };
1434
+ }
1435
+ encode(sdJwt, index) {
1436
+ return sdJwt.toEncoded(index);
1437
+ }
1438
+ decode(endcodedSDJwt) {
1439
+ return GeneralJSON.fromEncode(endcodedSDJwt);
1440
+ }
1441
+ async keys(generalSdjwt) {
1442
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1443
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1444
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).keys(this.userConfig.hasher);
1445
+ }
1446
+ async presentableKeys(generalSdjwt) {
1447
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1448
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1449
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).presentableKeys(this.userConfig.hasher);
1450
+ }
1451
+ async getClaims(generalSdjwt) {
1452
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1453
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1454
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).getClaims(this.userConfig.hasher);
1455
+ }
2036
1456
  };
1457
+ //#endregion
1458
+ export { DEFAULT_SECURE_HASH_ALGORITHMS, Disclosure, FlattenJSON, GeneralJSON, IANA_HASH_ALGORITHMS, Jwt, KBJwt, KB_JWT_TYP, SDJWTException, SDJwt, SDJwtGeneralJSONInstance, SDJwtInstance, SD_DECOY, SD_DIGEST, SD_LIST_KEY, SD_SEPARATOR, base64UrlToUint8Array, base64urlDecode, base64urlEncode, createDecoy, createHashMapping, createHashMappingForSerializedDisclosure, createHashMappingSync, decodeJwt, decodeSdJwt, decodeSdJwtSync, encodePath, encodePathSegment, ensureError, getClaims, getClaimsSync, getSDAlgAndPayload, listKeys, pack, present, presentSync, presentableKeys, presentableKeysSync, selectDisclosures, splitSdJwt, transformPresentationFrame, uint8ArrayToBase64Url, unpack, unpackObj, unpackSync, validateJwtPayload };
1459
+
1460
+ //# sourceMappingURL=index.mjs.map