@arcblock/jwt 1.29.14 → 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 +40 -1
- package/esm/index.mjs +111 -2
- package/lib/index.cjs +114 -1
- package/lib/index.d.cts +40 -1
- package/package.json +5 -5
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.
|
|
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.
|
|
23
|
-
"@ocap/mcrypto": "1.29.
|
|
24
|
-
"@ocap/util": "1.29.
|
|
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.
|
|
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",
|