@arcblock/jwt 1.16.14 → 1.16.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/index.d.ts +67 -16
  2. package/lib/index.js +173 -184
  3. package/package.json +24 -10
package/lib/index.d.ts CHANGED
@@ -1,16 +1,67 @@
1
- // Generate by [js2dts@0.3.3](https://github.com/whxaxes/js2dts#readme)
2
-
3
- declare const _Lib: _Lib.T102;
4
- declare namespace _Lib {
5
- export interface T101 {
6
- tolerance?: number;
7
- enforceTimestamp?: boolean;
8
- signerKey?: string;
9
- }
10
- export interface T102 {
11
- sign: (signer: string, sk: string, payload?: any, doSign?: boolean, version?: string) => string;
12
- verify: (token: string, signerPk: string, T100?: _Lib.T101) => boolean;
13
- decode: (token: string, payloadOnly?: boolean) => any;
14
- }
15
- }
16
- export = _Lib;
1
+ import { BytesType } from '@ocap/util';
2
+ export declare type JwtBody = {
3
+ iss?: string;
4
+ iat?: string;
5
+ nbf?: string;
6
+ exp?: string;
7
+ version?: string;
8
+ [key: string]: any;
9
+ };
10
+ export declare type JwtHeader = {
11
+ alg: string;
12
+ type: 'JWT';
13
+ };
14
+ export declare type JwtToken = {
15
+ header: JwtHeader;
16
+ body: JwtBody;
17
+ signature: string;
18
+ };
19
+ export declare type JwtVerifyOptions = Partial<{
20
+ tolerance: number;
21
+ enforceTimestamp: boolean;
22
+ signerKey: string;
23
+ }>;
24
+ /**
25
+ *
26
+ *
27
+ * @param {string} signer - address string
28
+ * @param {string} sk - hex encoded secret key
29
+ * @param {*} [payload={}] - data to be included before signing
30
+ * @param {boolean} [doSign=true] - do we need to sign the payload or just return the content to be signed
31
+ * @param {string} [version='1.0.0']
32
+ * @return {*} {string} - hex encoded signature
33
+ */
34
+ export declare function sign(signer: string, sk: string, payload?: {}, doSign?: boolean, version?: string): string;
35
+ /**
36
+ *
37
+ *
38
+ * @param {string} token - jwt string
39
+ * @param {boolean} [payloadOnly=true]
40
+ * @return {*} {{
41
+ * header: any;
42
+ * body: any;
43
+ * signature: string;
44
+ * }}
45
+ */
46
+ export declare function decode(token: string, payloadOnly?: boolean): JwtToken;
47
+ /**
48
+ *
49
+ *
50
+ * @param {string} token - the jwt token
51
+ * @param {string} signerPk - signer public key
52
+ * @param {{
53
+ * tolerance: number; - number of seconds to tolerant expire
54
+ * enforceTimestamp: boolean; - whether should be verify timestamps?
55
+ * signerKey: string; - which field should be used to pick the signer
56
+ * }} [{
57
+ * tolerance,
58
+ * enforceTimestamp,
59
+ * signerKey,
60
+ * }={
61
+ * tolerance: 5,
62
+ * enforceTimestamp: true,
63
+ * signerKey: 'iss',
64
+ * }]
65
+ * @return {*} {boolean}
66
+ */
67
+ export declare function verify(token: string, signerPk: BytesType, options?: JwtVerifyOptions): boolean;
package/lib/index.js CHANGED
@@ -1,206 +1,195 @@
1
- const semver = require('semver');
2
- const stringify = require('json-stable-stringify');
3
- const Mcrypto = require('@ocap/mcrypto');
4
- const { toHex, toBase64, fromBase64 } = require('@ocap/util');
5
- const { toDid, toStrictHex, toTypeInfo, isValid, isFromPublicKey } = require('@arcblock/did');
6
-
7
- // eslint-disable-next-line
8
- const debug = require('debug')(require('../package.json').name);
9
-
10
- const { types, getSigner } = Mcrypto;
11
-
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.verify = exports.decode = exports.sign = void 0;
7
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
8
+ const json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
9
+ const semver_1 = __importDefault(require("semver"));
10
+ const util_1 = require("@ocap/util");
11
+ const did_1 = require("@arcblock/did");
12
+ const mcrypto_1 = require("@ocap/mcrypto");
13
+ const debug_1 = __importDefault(require("debug"));
14
+ const debug = (0, debug_1.default)('@arcblock/jwt');
12
15
  // we start hashing before signing after 1.1
13
16
  const JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN = '1.1.0';
14
-
15
17
  // since ios requires a fixed length of input to sign, we use sha3 here before sign
16
- const hasher = Mcrypto.Hasher.SHA3.hash256;
17
-
18
+ const hasher = mcrypto_1.Hasher.SHA3.hash256;
18
19
  /**
19
- * Generate and sign a jwt token
20
20
  *
21
- * @public
22
- * @static
21
+ *
23
22
  * @param {string} signer - address string
24
23
  * @param {string} sk - hex encoded secret key
25
- * @param {object} [payload={}] - data to be included before signing
24
+ * @param {*} [payload={}] - data to be included before signing
26
25
  * @param {boolean} [doSign=true] - do we need to sign the payload or just return the content to be signed
27
- * @returns {string} hex encoded signature
26
+ * @param {string} [version='1.0.0']
27
+ * @return {*} {string} - hex encoded signature
28
28
  */
29
- const sign = (signer, sk, payload = {}, doSign = true, version = '1.0.0') => {
30
- if (isValid(signer) === false) {
31
- throw new Error('Cannot do sign with invalid signer');
32
- }
33
-
34
- const type = toTypeInfo(signer);
35
- const headers = {
36
- [types.KeyType.SECP256K1]: {
37
- alg: 'ES256K',
38
- type: 'JWT',
39
- },
40
- [types.KeyType.ED25519]: {
41
- alg: 'Ed25519',
42
- type: 'JWT',
43
- },
44
- [types.KeyType.ETHEREUM]: {
45
- alg: 'Ethereum',
46
- type: 'JWT',
47
- },
48
- };
49
-
50
- // make header
51
- const header = headers[type.pk];
52
- const headerB64 = toBase64(stringify(header));
53
-
54
- // make body
55
- const now = Math.floor(Date.now() / 1000);
56
- let body = {
57
- iss: toDid(signer),
58
- iat: String(now),
59
- nbf: String(now),
60
- exp: String(now + 5 * 60),
61
- version,
62
- ...(payload || {}),
63
- };
64
- // remove empty keys
65
- body = Object.keys(body)
66
- .filter((x) => {
67
- if (typeof body[x] === 'undefined' || body[x] == null || body[x] === '') {
68
- return false;
69
- }
70
-
71
- return true;
29
+ function sign(signer, sk, payload = {}, doSign = true, version = '1.0.0') {
30
+ if ((0, did_1.isValid)(signer) === false) {
31
+ throw new Error('Cannot do sign with invalid signer');
32
+ }
33
+ const type = (0, did_1.toTypeInfo)(signer);
34
+ const headers = {
35
+ [mcrypto_1.types.KeyType.SECP256K1]: {
36
+ alg: 'ES256K',
37
+ type: 'JWT',
38
+ },
39
+ [mcrypto_1.types.KeyType.ED25519]: {
40
+ alg: 'Ed25519',
41
+ type: 'JWT',
42
+ },
43
+ [mcrypto_1.types.KeyType.ETHEREUM]: {
44
+ alg: 'Ethereum',
45
+ type: 'JWT',
46
+ },
47
+ };
48
+ // make header
49
+ const header = headers[type.pk];
50
+ const headerB64 = (0, util_1.toBase64)((0, json_stable_stringify_1.default)(header));
51
+ // make body
52
+ const now = Math.floor(Date.now() / 1000);
53
+ let body = Object.assign({ iss: (0, did_1.toDid)(signer), iat: String(now), nbf: String(now), exp: String(now + 5 * 60), version }, (payload || {}));
54
+ // remove empty keys
55
+ body = Object.keys(body)
56
+ .filter((x) => {
57
+ if (typeof body[x] === 'undefined' || body[x] == null || body[x] === '') {
58
+ return false;
59
+ }
60
+ return true;
72
61
  })
73
- .reduce((acc, x) => {
74
- acc[x] = body[x];
75
- return acc;
62
+ .reduce((acc, x) => {
63
+ acc[x] = body[x];
64
+ return acc;
76
65
  }, {});
77
-
78
- const bodyB64 = toBase64(stringify(body));
79
- debug('sign.body', body);
80
-
81
- // istanbul ignore if
82
- if (!doSign) {
83
- return `${headerB64}.${bodyB64}`;
84
- }
85
-
86
- // make signature
87
- const msgHex = toHex(`${headerB64}.${bodyB64}`);
88
- const msgHash = semver.gte(semver.coerce(version).version, JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN)
89
- ? hasher(msgHex)
90
- : msgHex;
91
- const sigHex = getSigner(type.pk).sign(msgHash, sk);
92
- const sigB64 = toBase64(sigHex);
93
-
94
- return [headerB64, bodyB64, sigB64].join('.');
95
- };
96
-
66
+ const bodyB64 = (0, util_1.toBase64)((0, json_stable_stringify_1.default)(body));
67
+ debug('sign.body', body);
68
+ // istanbul ignore if
69
+ if (!doSign) {
70
+ return `${headerB64}.${bodyB64}`;
71
+ }
72
+ // @ts-ignore make signature
73
+ const msgHex = (0, util_1.toHex)(`${headerB64}.${bodyB64}`);
74
+ const msgHash = semver_1.default.gte(semver_1.default.coerce(version).version, JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN)
75
+ ? hasher(msgHex)
76
+ : msgHex;
77
+ const sigHex = (0, mcrypto_1.getSigner)(type.pk).sign(msgHash, sk);
78
+ const sigB64 = (0, util_1.toBase64)(sigHex);
79
+ return [headerB64, bodyB64, sigB64].join('.');
80
+ }
81
+ exports.sign = sign;
97
82
  /**
98
- * Decode info from jwt token
99
83
  *
100
- * @public
101
- * @static
84
+ *
102
85
  * @param {string} token - jwt string
103
- * @param {boolean} [payloadOnly=false]
104
- * @returns {object}
86
+ * @param {boolean} [payloadOnly=true]
87
+ * @return {*} {{
88
+ * header: any;
89
+ * body: any;
90
+ * signature: string;
91
+ * }}
105
92
  */
106
- const decode = (token, payloadOnly = true) => {
107
- const [headerB64, bodyB64, sigB64] = token.split('.');
108
- const header = JSON.parse(fromBase64(headerB64));
109
- const body = JSON.parse(fromBase64(bodyB64));
110
- const sig = Buffer.from(fromBase64(sigB64)).toString('hex');
111
- if (payloadOnly) {
112
- return body;
113
- }
114
- return { header, body, signature: `0x${toStrictHex(sig)}` };
115
- };
116
-
93
+ function decode(token, payloadOnly = true) {
94
+ const [headerB64, bodyB64, sigB64] = token.split('.');
95
+ const header = JSON.parse((0, util_1.fromBase64)(headerB64).toString());
96
+ const body = JSON.parse((0, util_1.fromBase64)(bodyB64).toString());
97
+ const sig = Buffer.from((0, util_1.fromBase64)(sigB64)).toString('hex');
98
+ if (payloadOnly) {
99
+ return body;
100
+ }
101
+ return { header, body, signature: `0x${(0, did_1.toStrictHex)(sig)}` };
102
+ }
103
+ exports.decode = decode;
117
104
  /**
118
- * Verify a jwt token signed with signerPk and signerDid
119
105
  *
120
- * @public
121
- * @static
122
- * @param {string} token - the jwt token
106
+ *
107
+ * @param {string} token - the jwt token
123
108
  * @param {string} signerPk - signer public key
124
- * @param {object} options - options to customize the verify
125
- * @param {number} [options.tolerance=5] - number of seconds to tolerant expire
126
- * @param {boolean} [options.enforceTimestamp=true] - whether should be verify timestamps?
127
- * @param {string} [options.signerKey='iss'] - which field should be used to pick the signer
128
- * @returns {boolean}
109
+ * @param {{
110
+ * tolerance: number; - number of seconds to tolerant expire
111
+ * enforceTimestamp: boolean; - whether should be verify timestamps?
112
+ * signerKey: string; - which field should be used to pick the signer
113
+ * }} [{
114
+ * tolerance,
115
+ * enforceTimestamp,
116
+ * signerKey,
117
+ * }={
118
+ * tolerance: 5,
119
+ * enforceTimestamp: true,
120
+ * signerKey: 'iss',
121
+ * }]
122
+ * @return {*} {boolean}
129
123
  */
130
- const verify = (token, signerPk, { tolerance = 5, enforceTimestamp = true, signerKey = 'iss' } = {}) => {
131
- try {
132
- const [headerB64, bodyB64] = token.split('.');
133
- const { header, body, signature } = decode(token, false);
134
- if (!signature) {
135
- debug('verify.error.emptySig');
136
- return false;
137
- }
138
- if (!header.alg) {
139
- debug('verify.error.emptyAlg');
140
- return false;
141
- }
142
-
143
- const signerDid = body[signerKey];
144
- if (!signerDid) {
145
- debug('verify.error.emptySignerDid');
146
- return false;
147
- }
148
-
149
- if (isFromPublicKey(signerDid, signerPk) === false) {
150
- debug('verify.error.signerDidAndPkNotMatch');
151
- return false;
152
- }
153
-
154
- if (enforceTimestamp) {
155
- const now = Math.ceil(Date.now() / 1000);
156
- const exp = Number(body.exp) || 0;
157
- const iat = Number(body.iat) || 0;
158
- const nbf = Number(body.nbf) || 0;
159
- debug('verify.enforceTimestamp', { now, exp, iat, nbf });
160
- if (exp && exp + tolerance < now) {
161
- debug('verify.error.expired');
162
- return false;
163
- }
164
- if (iat && iat > now && iat - now > tolerance) {
165
- debug('verify.error.issuedAt');
124
+ function verify(token, signerPk, options) {
125
+ const { tolerance, enforceTimestamp, signerKey } = Object.assign({
126
+ tolerance: 5,
127
+ enforceTimestamp: true,
128
+ signerKey: 'iss',
129
+ }, options);
130
+ try {
131
+ const [headerB64, bodyB64] = token.split('.');
132
+ const { header, body, signature } = decode(token, false);
133
+ if (!signature) {
134
+ debug('verify.error.emptySig');
135
+ return false;
136
+ }
137
+ if (!header.alg) {
138
+ debug('verify.error.emptyAlg');
139
+ return false;
140
+ }
141
+ const signerDid = body[signerKey];
142
+ if (!signerDid) {
143
+ debug('verify.error.emptySignerDid');
144
+ return false;
145
+ }
146
+ if ((0, did_1.isFromPublicKey)(signerDid, signerPk) === false) {
147
+ debug('verify.error.signerDidAndPkNotMatch');
148
+ return false;
149
+ }
150
+ if (enforceTimestamp) {
151
+ const now = Math.ceil(Date.now() / 1000);
152
+ const exp = Number(body.exp) || 0;
153
+ const iat = Number(body.iat) || 0;
154
+ const nbf = Number(body.nbf) || 0;
155
+ debug('verify.enforceTimestamp', { now, exp, iat, nbf });
156
+ if (exp && exp + tolerance < now) {
157
+ debug('verify.error.expired');
158
+ return false;
159
+ }
160
+ if (iat && iat > now && iat - now > tolerance) {
161
+ debug('verify.error.issuedAt');
162
+ return false;
163
+ }
164
+ if (nbf && nbf > now && nbf - now > tolerance) {
165
+ debug('verify.error.notBefore');
166
+ return false;
167
+ }
168
+ }
169
+ const signers = {
170
+ secp256k1: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.SECP256K1),
171
+ es256k: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.SECP256K1),
172
+ ed25519: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.ED25519),
173
+ ethereum: (0, mcrypto_1.getSigner)(mcrypto_1.types.KeyType.ETHEREUM),
174
+ };
175
+ const alg = header.alg.toLowerCase();
176
+ if (signers[alg]) {
177
+ // @ts-ignore
178
+ const msgHex = (0, util_1.toHex)(`${headerB64}.${bodyB64}`);
179
+ // If we are using v1.1 protocol, the message should be hashed before verify
180
+ const version = body.version && semver_1.default.coerce(body.version) ? semver_1.default.coerce(body.version).version : '';
181
+ if (version && version === JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN) {
182
+ return signers[alg].verify(hasher(msgHex), signature, signerPk);
183
+ }
184
+ return signers[alg].verify(msgHex, signature, signerPk);
185
+ }
186
+ debug('verify.error.crypto');
166
187
  return false;
167
- }
168
- if (nbf && nbf > now && nbf - now > tolerance) {
169
- debug('verify.error.notBefore');
170
- return false;
171
- }
172
188
  }
173
-
174
- const signers = {
175
- secp256k1: getSigner(types.KeyType.SECP256K1),
176
- es256k: getSigner(types.KeyType.SECP256K1),
177
- ed25519: getSigner(types.KeyType.ED25519),
178
- ethereum: getSigner(types.KeyType.ETHEREUM),
179
- };
180
- const alg = header.alg.toLowerCase();
181
- if (signers[alg]) {
182
- const msgHex = toHex(`${headerB64}.${bodyB64}`);
183
-
184
- // If we are using v1.1 protocol, the message should be hashed before verify
185
- const version = body.version && semver.coerce(body.version) ? semver.coerce(body.version).version : '';
186
- if (version && version === JWT_VERSION_REQUIRE_HASH_BEFORE_SIGN) {
187
- return signers[alg].verify(hasher(msgHex), signature, signerPk);
188
- }
189
-
190
- return signers[alg].verify(msgHex, signature, signerPk);
189
+ catch (err) {
190
+ debug('verify.error.exception');
191
+ debug(err);
192
+ return false;
191
193
  }
192
-
193
- debug('verify.error.crypto');
194
- return false;
195
- } catch (err) {
196
- debug('verify.error.exception');
197
- debug(err);
198
- return false;
199
- }
200
- };
201
-
202
- module.exports = {
203
- sign,
204
- verify,
205
- decode,
206
- };
194
+ }
195
+ exports.verify = verify;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcblock/jwt",
3
3
  "description": "JSON Web Token variant for arcblock DID solutions",
4
- "version": "1.16.14",
4
+ "version": "1.16.17",
5
5
  "author": {
6
6
  "name": "wangshijun",
7
7
  "email": "shijun@arcblock.io",
@@ -18,15 +18,24 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@arcblock/did": "1.16.14",
22
- "@ocap/mcrypto": "1.16.14",
23
- "@ocap/util": "1.16.14",
21
+ "@arcblock/did": "1.16.17",
22
+ "@ocap/mcrypto": "1.16.17",
23
+ "@ocap/util": "1.16.17",
24
24
  "debug": "^4.3.3",
25
25
  "json-stable-stringify": "^1.0.1",
26
26
  "semver": "^7.3.4"
27
27
  },
28
28
  "devDependencies": {
29
- "jest": "^27.3.1"
29
+ "@arcblock/eslint-config-ts": "0.2.2",
30
+ "@types/jest": "^27.5.1",
31
+ "@types/json-stable-stringify": "^1.0.34",
32
+ "@types/node": "^17.0.33",
33
+ "@types/semver": "^7.3.9",
34
+ "eslint": "^8.17.0",
35
+ "jest": "^27.3.1",
36
+ "ts-jest": "^28.0.0",
37
+ "tslib": "^2.4.0",
38
+ "typescript": "^4.6.4"
30
39
  },
31
40
  "homepage": "https://github.com/ArcBlock/asset-chain/tree/master/did/jwt",
32
41
  "keywords": [
@@ -36,7 +45,8 @@
36
45
  "nodejs"
37
46
  ],
38
47
  "license": "Apache-2.0",
39
- "main": "./lib/index.js",
48
+ "main": "lib/index.js",
49
+ "typings": "lib/index.d.ts",
40
50
  "files": [
41
51
  "lib"
42
52
  ],
@@ -45,10 +55,14 @@
45
55
  "url": "https://github.com/ArcBlock/asset-chain/tree/master/did/jwt"
46
56
  },
47
57
  "scripts": {
48
- "lint": "eslint lib tests",
49
- "lint:fix": "eslint --fix lib tests",
58
+ "lint": "eslint src tests",
59
+ "lint:fix": "eslint src tests --fix",
50
60
  "test": "jest --forceExit --detectOpenHandles",
51
- "coverage": "yarn test -- --coverage"
61
+ "coverage": "yarn test -- --coverage",
62
+ "clean": "rm -fr lib",
63
+ "prebuild": "npm run clean",
64
+ "build:watch": "npm run build -- -w",
65
+ "build": "tsc"
52
66
  },
53
- "gitHead": "5f1bb9c7d6044e20c77e9cccea8cda2d6c5ae29f"
67
+ "gitHead": "489ce5e03bce27ddcd535390228b11ab56e7a2e3"
54
68
  }