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