@arcblock/jwt 1.29.13 → 1.29.15

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/esm/index.d.mts CHANGED
@@ -58,5 +58,44 @@ declare function decode(token: string, bodyOnly?: false): JwtToken;
58
58
  * @return {*} {boolean}
59
59
  */
60
60
  declare function verify(token: string, signerPk: BytesType, options?: JwtVerifyOptions): Promise<boolean>;
61
+ type DelegationTokenHeader = {
62
+ alg: string;
63
+ typ: 'DelegationToken';
64
+ };
65
+ type DelegationTokenBody = {
66
+ iss: string;
67
+ sub: string;
68
+ iat: string;
69
+ nbf: string;
70
+ exp: string;
71
+ version: string;
72
+ ops: string[];
73
+ deny?: string[];
74
+ pk: string;
75
+ delegation?: string;
76
+ };
77
+ type DelegationToken = {
78
+ header: DelegationTokenHeader;
79
+ body: DelegationTokenBody;
80
+ signature: string;
81
+ };
82
+ declare function signDelegationToken(signer: string, sk: BytesType, payload: {
83
+ sub: string;
84
+ ops: string[];
85
+ deny?: string[];
86
+ delegation?: string;
87
+ iat?: string;
88
+ nbf?: string;
89
+ exp?: string;
90
+ }): Promise<string>;
91
+ declare function decodeDelegationToken(token: string): DelegationToken;
92
+ declare function verifyDelegationToken(token: string): Promise<boolean>;
93
+ declare function checkDelegationTokenScope(scope: string, {
94
+ ops,
95
+ deny
96
+ }: {
97
+ ops: string[];
98
+ deny?: string[];
99
+ }): boolean;
61
100
  //#endregion
62
- export { JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, decode, sign, signV2, verify };
101
+ export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
package/esm/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isFromPublicKey, isValid, toDid, toStrictHex, toTypeInfo } from "@arcblock/did";
2
2
  import { Hasher, getSigner, types } from "@ocap/mcrypto";
3
- import { fromBase64, toBase64, toHex } from "@ocap/util";
3
+ import { fromBase64, scopeMatchAny, toBase64, toHex } from "@ocap/util";
4
4
  import Debug from "debug";
5
5
  import stringify from "json-stable-stringify";
6
6
  import semver from "semver";
@@ -176,6 +176,115 @@ async function verify(token, signerPk, options) {
176
176
  return false;
177
177
  }
178
178
  }
179
+ const DELEGATION_TOKEN_VERSION = "1.1.0";
180
+ const delegationTokenHeaders = {
181
+ [types.KeyType.ED25519]: {
182
+ alg: "Ed25519",
183
+ typ: "DelegationToken"
184
+ },
185
+ [types.KeyType.SECP256K1]: {
186
+ alg: "ES256K",
187
+ typ: "DelegationToken"
188
+ },
189
+ [types.KeyType.ETHEREUM]: {
190
+ alg: "Ethereum",
191
+ typ: "DelegationToken"
192
+ }
193
+ };
194
+ async function signDelegationToken(signer, sk, payload) {
195
+ if (isValid(signer) === false) throw new Error("Cannot sign DelegationToken with invalid signer");
196
+ const type = toTypeInfo(signer);
197
+ if (type.pk === void 0) throw new Error("Cannot determine key type from signer");
198
+ const header = delegationTokenHeaders[type.pk];
199
+ const headerB64 = toBase64(stringify(header));
200
+ const now = Math.floor(Date.now() / 1e3);
201
+ const body = {
202
+ iss: toDid(signer),
203
+ sub: payload.sub,
204
+ iat: payload.iat || String(now),
205
+ nbf: payload.nbf || String(now),
206
+ exp: payload.exp || String(now + 300),
207
+ version: DELEGATION_TOKEN_VERSION,
208
+ ops: payload.ops,
209
+ pk: getSigner(type.pk).getPublicKey(sk, "hex")
210
+ };
211
+ if (payload.deny && payload.deny.length > 0) {
212
+ for (const d of payload.deny) if (!d.startsWith("fg:")) throw new Error(`Invalid deny pattern "${d}": must start with "fg:"`);
213
+ body.deny = payload.deny;
214
+ }
215
+ if (payload.delegation) body.delegation = payload.delegation;
216
+ const bodyB64 = toBase64(stringify(body));
217
+ const msgHash = hasher(toHex(`${headerB64}.${bodyB64}`));
218
+ return [
219
+ headerB64,
220
+ bodyB64,
221
+ toBase64(getSigner(type.pk).sign(msgHash, sk))
222
+ ].join(".");
223
+ }
224
+ function decodeDelegationToken(token) {
225
+ const parts = token.split(".");
226
+ if (parts.length !== 3) throw new Error("Invalid delegation token format: expected 3 parts");
227
+ const [headerB64, bodyB64, sigB64] = parts;
228
+ return {
229
+ header: JSON.parse(fromBase64(headerB64).toString()),
230
+ body: JSON.parse(fromBase64(bodyB64).toString()),
231
+ signature: `0x${toStrictHex(Buffer.from(Uint8Array.from(fromBase64(sigB64))).toString("hex"))}`
232
+ };
233
+ }
234
+ async function verifyDelegationToken(token) {
235
+ try {
236
+ const [headerB64, bodyB64] = token.split(".");
237
+ const { header, body, signature } = decodeDelegationToken(token);
238
+ if (header.typ !== "DelegationToken") {
239
+ debug("delegationToken.verify.error.wrongTyp");
240
+ return false;
241
+ }
242
+ if (!signature || !header.alg) {
243
+ debug("delegationToken.verify.error.missingSigOrAlg");
244
+ return false;
245
+ }
246
+ if (isFromPublicKey(body.iss, body.pk) === false) {
247
+ debug("delegationToken.verify.error.pkIssMismatch");
248
+ return false;
249
+ }
250
+ const now = Math.floor(Date.now() / 1e3);
251
+ const exp = Number(body.exp) || 0;
252
+ const nbf = Number(body.nbf) || 0;
253
+ const iat = Number(body.iat) || 0;
254
+ if (exp && exp < now) {
255
+ debug("delegationToken.verify.error.expired");
256
+ return false;
257
+ }
258
+ if (nbf && nbf > now) {
259
+ debug("delegationToken.verify.error.notYetValid");
260
+ return false;
261
+ }
262
+ if (iat && iat > now) {
263
+ debug("delegationToken.verify.error.futureIat");
264
+ return false;
265
+ }
266
+ const signers = {
267
+ ed25519: getSigner(types.KeyType.ED25519),
268
+ es256k: getSigner(types.KeyType.SECP256K1),
269
+ secp256k1: getSigner(types.KeyType.SECP256K1),
270
+ ethereum: getSigner(types.KeyType.ETHEREUM)
271
+ };
272
+ const alg = header.alg.toLowerCase();
273
+ if (!signers[alg]) {
274
+ debug("delegationToken.verify.error.unknownAlg");
275
+ return false;
276
+ }
277
+ const msgHash = hasher(toHex(`${headerB64}.${bodyB64}`));
278
+ return signers[alg].verify(msgHash, signature, body.pk);
279
+ } catch (err) {
280
+ debug("delegationToken.verify.error.exception", err);
281
+ return false;
282
+ }
283
+ }
284
+ function checkDelegationTokenScope(scope, { ops, deny }) {
285
+ if (deny && deny.length > 0 && scopeMatchAny(scope, deny)) return false;
286
+ return scopeMatchAny(scope, ops);
287
+ }
179
288
 
180
289
  //#endregion
181
- export { decode, sign, signV2, verify };
290
+ export { checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
package/lib/index.cjs CHANGED
@@ -180,9 +180,122 @@ async function verify(token, signerPk, options) {
180
180
  return false;
181
181
  }
182
182
  }
183
+ const DELEGATION_TOKEN_VERSION = "1.1.0";
184
+ const delegationTokenHeaders = {
185
+ [_ocap_mcrypto.types.KeyType.ED25519]: {
186
+ alg: "Ed25519",
187
+ typ: "DelegationToken"
188
+ },
189
+ [_ocap_mcrypto.types.KeyType.SECP256K1]: {
190
+ alg: "ES256K",
191
+ typ: "DelegationToken"
192
+ },
193
+ [_ocap_mcrypto.types.KeyType.ETHEREUM]: {
194
+ alg: "Ethereum",
195
+ typ: "DelegationToken"
196
+ }
197
+ };
198
+ async function signDelegationToken(signer, sk, payload) {
199
+ if ((0, _arcblock_did.isValid)(signer) === false) throw new Error("Cannot sign DelegationToken with invalid signer");
200
+ const type = (0, _arcblock_did.toTypeInfo)(signer);
201
+ if (type.pk === void 0) throw new Error("Cannot determine key type from signer");
202
+ const header = delegationTokenHeaders[type.pk];
203
+ const headerB64 = (0, _ocap_util.toBase64)((0, json_stable_stringify.default)(header));
204
+ const now = Math.floor(Date.now() / 1e3);
205
+ const body = {
206
+ iss: (0, _arcblock_did.toDid)(signer),
207
+ sub: payload.sub,
208
+ iat: payload.iat || String(now),
209
+ nbf: payload.nbf || String(now),
210
+ exp: payload.exp || String(now + 300),
211
+ version: DELEGATION_TOKEN_VERSION,
212
+ ops: payload.ops,
213
+ pk: (0, _ocap_mcrypto.getSigner)(type.pk).getPublicKey(sk, "hex")
214
+ };
215
+ if (payload.deny && payload.deny.length > 0) {
216
+ for (const d of payload.deny) if (!d.startsWith("fg:")) throw new Error(`Invalid deny pattern "${d}": must start with "fg:"`);
217
+ body.deny = payload.deny;
218
+ }
219
+ if (payload.delegation) body.delegation = payload.delegation;
220
+ const bodyB64 = (0, _ocap_util.toBase64)((0, json_stable_stringify.default)(body));
221
+ const msgHash = hasher((0, _ocap_util.toHex)(`${headerB64}.${bodyB64}`));
222
+ return [
223
+ headerB64,
224
+ bodyB64,
225
+ (0, _ocap_util.toBase64)((0, _ocap_mcrypto.getSigner)(type.pk).sign(msgHash, sk))
226
+ ].join(".");
227
+ }
228
+ function decodeDelegationToken(token) {
229
+ const parts = token.split(".");
230
+ if (parts.length !== 3) throw new Error("Invalid delegation token format: expected 3 parts");
231
+ const [headerB64, bodyB64, sigB64] = parts;
232
+ return {
233
+ header: JSON.parse((0, _ocap_util.fromBase64)(headerB64).toString()),
234
+ body: JSON.parse((0, _ocap_util.fromBase64)(bodyB64).toString()),
235
+ signature: `0x${(0, _arcblock_did.toStrictHex)(Buffer.from(Uint8Array.from((0, _ocap_util.fromBase64)(sigB64))).toString("hex"))}`
236
+ };
237
+ }
238
+ async function verifyDelegationToken(token) {
239
+ try {
240
+ const [headerB64, bodyB64] = token.split(".");
241
+ const { header, body, signature } = decodeDelegationToken(token);
242
+ if (header.typ !== "DelegationToken") {
243
+ debug$1("delegationToken.verify.error.wrongTyp");
244
+ return false;
245
+ }
246
+ if (!signature || !header.alg) {
247
+ debug$1("delegationToken.verify.error.missingSigOrAlg");
248
+ return false;
249
+ }
250
+ if ((0, _arcblock_did.isFromPublicKey)(body.iss, body.pk) === false) {
251
+ debug$1("delegationToken.verify.error.pkIssMismatch");
252
+ return false;
253
+ }
254
+ const now = Math.floor(Date.now() / 1e3);
255
+ const exp = Number(body.exp) || 0;
256
+ const nbf = Number(body.nbf) || 0;
257
+ const iat = Number(body.iat) || 0;
258
+ if (exp && exp < now) {
259
+ debug$1("delegationToken.verify.error.expired");
260
+ return false;
261
+ }
262
+ if (nbf && nbf > now) {
263
+ debug$1("delegationToken.verify.error.notYetValid");
264
+ return false;
265
+ }
266
+ if (iat && iat > now) {
267
+ debug$1("delegationToken.verify.error.futureIat");
268
+ return false;
269
+ }
270
+ const signers = {
271
+ ed25519: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ED25519),
272
+ es256k: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
273
+ secp256k1: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
274
+ ethereum: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ETHEREUM)
275
+ };
276
+ const alg = header.alg.toLowerCase();
277
+ if (!signers[alg]) {
278
+ debug$1("delegationToken.verify.error.unknownAlg");
279
+ return false;
280
+ }
281
+ const msgHash = hasher((0, _ocap_util.toHex)(`${headerB64}.${bodyB64}`));
282
+ return signers[alg].verify(msgHash, signature, body.pk);
283
+ } catch (err) {
284
+ debug$1("delegationToken.verify.error.exception", err);
285
+ return false;
286
+ }
287
+ }
288
+ function checkDelegationTokenScope(scope, { ops, deny }) {
289
+ if (deny && deny.length > 0 && (0, _ocap_util.scopeMatchAny)(scope, deny)) return false;
290
+ return (0, _ocap_util.scopeMatchAny)(scope, ops);
291
+ }
183
292
 
184
293
  //#endregion
294
+ exports.checkDelegationTokenScope = checkDelegationTokenScope;
185
295
  exports.decode = decode;
296
+ exports.decodeDelegationToken = decodeDelegationToken;
186
297
  exports.sign = sign;
298
+ exports.signDelegationToken = signDelegationToken;
187
299
  exports.signV2 = signV2;
188
- exports.verify = verify;
300
+ exports.verify = verify;
301
+ exports.verifyDelegationToken = verifyDelegationToken;
package/lib/index.d.cts CHANGED
@@ -58,5 +58,44 @@ declare function decode(token: string, bodyOnly?: false): JwtToken;
58
58
  * @return {*} {boolean}
59
59
  */
60
60
  declare function verify(token: string, signerPk: BytesType, options?: JwtVerifyOptions): Promise<boolean>;
61
+ type DelegationTokenHeader = {
62
+ alg: string;
63
+ typ: 'DelegationToken';
64
+ };
65
+ type DelegationTokenBody = {
66
+ iss: string;
67
+ sub: string;
68
+ iat: string;
69
+ nbf: string;
70
+ exp: string;
71
+ version: string;
72
+ ops: string[];
73
+ deny?: string[];
74
+ pk: string;
75
+ delegation?: string;
76
+ };
77
+ type DelegationToken = {
78
+ header: DelegationTokenHeader;
79
+ body: DelegationTokenBody;
80
+ signature: string;
81
+ };
82
+ declare function signDelegationToken(signer: string, sk: BytesType, payload: {
83
+ sub: string;
84
+ ops: string[];
85
+ deny?: string[];
86
+ delegation?: string;
87
+ iat?: string;
88
+ nbf?: string;
89
+ exp?: string;
90
+ }): Promise<string>;
91
+ declare function decodeDelegationToken(token: string): DelegationToken;
92
+ declare function verifyDelegationToken(token: string): Promise<boolean>;
93
+ declare function checkDelegationTokenScope(scope: string, {
94
+ ops,
95
+ deny
96
+ }: {
97
+ ops: string[];
98
+ deny?: string[];
99
+ }): boolean;
61
100
  //#endregion
62
- export { JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, decode, sign, signV2, verify };
101
+ export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@arcblock/jwt",
3
3
  "description": "JSON Web Token variant for arcblock DID solutions",
4
4
  "type": "module",
5
- "version": "1.29.13",
5
+ "version": "1.29.15",
6
6
  "author": {
7
7
  "name": "wangshijun",
8
8
  "email": "shijun@arcblock.io",
@@ -19,15 +19,15 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@arcblock/did": "1.29.13",
23
- "@ocap/mcrypto": "1.29.13",
24
- "@ocap/util": "1.29.13",
22
+ "@arcblock/did": "1.29.15",
23
+ "@ocap/mcrypto": "1.29.15",
24
+ "@ocap/util": "1.29.15",
25
25
  "debug": "^4.4.3",
26
26
  "json-stable-stringify": "^1.0.1",
27
27
  "semver": "^7.6.3"
28
28
  },
29
29
  "devDependencies": {
30
- "@ocap/wallet": "1.29.13",
30
+ "@ocap/wallet": "1.29.15",
31
31
  "@types/json-stable-stringify": "^1.0.36",
32
32
  "@types/node": "^22.7.5",
33
33
  "@types/semver": "^7.5.8",