lacewing 1.2.0 → 1.2.1
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 +23 -38
- package/GETTING-STARTED.md +5 -0
- package/README.md +11 -3
- package/dist/src/cookbook/access-refresh.js +4 -3
- package/dist/src/cookbook/access-refresh.js.map +1 -1
- package/dist/src/jwks/local.js +24 -5
- package/dist/src/jwks/local.js.map +1 -1
- package/dist/src/jwks/remote.js +3 -3
- package/dist/src/jwks/remote.js.map +1 -1
- package/dist/src/jwt/verify.js +13 -1
- package/dist/src/jwt/verify.js.map +1 -1
- package/dist/src/lib/entropy.js +94 -7
- package/dist/src/lib/entropy.js.map +1 -1
- package/dist/types/src/cookbook/access-refresh.d.ts +4 -3
- package/dist/types/src/cookbook/access-refresh.d.ts.map +1 -1
- package/dist/types/src/jwks/local.d.ts +2 -2
- package/dist/types/src/jwks/local.d.ts.map +1 -1
- package/dist/types/src/jwks/remote.d.ts.map +1 -1
- package/dist/types/src/jwt/verify.d.ts.map +1 -1
- package/dist/types/src/lib/entropy.d.ts +15 -0
- package/dist/types/src/lib/entropy.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.1] - 2026-10-10
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Bind keys without alg and custom key sources to one algorithm
|
|
10
|
+
- Accept only encoded random keys as printable hmac secrets
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
|
|
14
|
+
- State what lacewing cannot enforce and where the crypto comes from
|
|
15
|
+
|
|
16
|
+
### Miscellaneous Tasks
|
|
17
|
+
|
|
18
|
+
- Bumped version
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- Skip dependabot deps-dev commits and match security in any case
|
|
23
|
+
|
|
5
24
|
## [1.2.0] - 2026-09-26
|
|
6
25
|
|
|
7
26
|
### Features
|
|
@@ -21,40 +40,7 @@ All notable changes to this project will be documented in this file.
|
|
|
21
40
|
|
|
22
41
|
### Miscellaneous Tasks
|
|
23
42
|
|
|
24
|
-
- Bump tsx from 4.23.1 to 4.23.5
|
|
25
|
-
- Bump typescript-eslint from 8.65.0 to 8.66.0
|
|
26
|
-
- Bump tsx from 4.23.5 to 4.23.9
|
|
27
|
-
- Bump eslint from 10.8.0 to 10.8.1
|
|
28
|
-
- Bump tsx from 4.23.9 to 4.23.11
|
|
29
|
-
- Bump @types/node from 26.1.2 to 26.2.0
|
|
30
|
-
- Bump tsx from 4.23.11 to 4.23.12
|
|
31
|
-
- Bump typescript-eslint from 8.66.0 to 8.67.0
|
|
32
|
-
- Bump @commitlint/cli from 21.2.1 to 21.2.2
|
|
33
|
-
- Bump @commitlint/config-conventional
|
|
34
|
-
- Bump typescript-eslint from 8.67.0 to 8.68.0
|
|
35
|
-
- Bump @types/node from 26.2.0 to 26.3.0
|
|
36
|
-
- Bump eslint from 10.9.0 to 10.9.1
|
|
37
|
-
- Bump @types/node from 26.3.0 to 26.4.0
|
|
38
|
-
- Bump lefthook from 2.1.10 to 2.1.12
|
|
39
|
-
- Bump tsx from 4.23.12 to 4.23.13
|
|
40
|
-
- Bump typescript-eslint from 8.68.0 to 8.69.0
|
|
41
|
-
- Bump @types/node from 26.4.0 to 26.4.1
|
|
42
|
-
- Bump eslint from 10.9.1 to 10.10.0
|
|
43
|
-
- Bump typescript-eslint from 8.69.0 to 8.70.0
|
|
44
|
-
- Bump @types/node from 26.4.1 to 26.5.0
|
|
45
|
-
- Bump @types/node from 26.5.0 to 26.5.1
|
|
46
|
-
- Bump fast-check from 4.9.0 to 4.10.0
|
|
47
|
-
- Bump lefthook from 2.1.12 to 2.1.14
|
|
48
43
|
- Added long overdue document
|
|
49
|
-
- Bump fast-check from 4.10.0 to 4.10.1
|
|
50
|
-
- Bump git-cliff from 2.13.1 to 2.14.2
|
|
51
|
-
- Bump @types/node from 26.5.1 to 26.6.2
|
|
52
|
-
- Bump eslint from 10.10.0 to 10.11.0
|
|
53
|
-
- Bump @commitlint/config-conventional
|
|
54
|
-
- Bump @commitlint/cli from 21.2.2 to 21.2.3
|
|
55
|
-
- Bump fast-check from 4.10.1 to 4.10.2
|
|
56
|
-
- Bump tsx from 4.23.13 to 4.23.15
|
|
57
|
-
- Bump typescript-eslint from 8.70.0 to 8.70.1
|
|
58
44
|
- Adjusted dist dir with more strictness
|
|
59
45
|
|
|
60
46
|
### Testing
|
|
@@ -73,9 +59,12 @@ All notable changes to this project will be documented in this file.
|
|
|
73
59
|
|
|
74
60
|
### Miscellaneous Tasks
|
|
75
61
|
|
|
76
|
-
- Create SECURITY.md for security policy
|
|
77
62
|
- Added quick start to typedoc
|
|
78
63
|
|
|
64
|
+
### Security
|
|
65
|
+
|
|
66
|
+
- Create SECURITY.md for security policy
|
|
67
|
+
|
|
79
68
|
## [1.0.1] - 2026-07-29
|
|
80
69
|
|
|
81
70
|
### Bug Fixes
|
|
@@ -98,11 +87,7 @@ All notable changes to this project will be documented in this file.
|
|
|
98
87
|
|
|
99
88
|
### Miscellaneous Tasks
|
|
100
89
|
|
|
101
|
-
- Bump typescript-eslint from 8.63.0 to 8.64.0
|
|
102
|
-
- Bump tsx from 4.23.0 to 4.23.1
|
|
103
|
-
- Bump typescript-eslint from 8.64.0 to 8.65.0
|
|
104
90
|
- Bumped various deps
|
|
105
|
-
- Bump @types/node from 26.1.1 to 26.1.2
|
|
106
91
|
|
|
107
92
|
## [1.0.0] - 2026-07-12
|
|
108
93
|
|
package/GETTING-STARTED.md
CHANGED
|
@@ -153,6 +153,11 @@ secret fails at startup instead of producing weak signatures:
|
|
|
153
153
|
await importKey("my-secret-password-123", "HS256"); // throws EntropyCheckFailed
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
A string secret must be random bytes written as hex or base64(url), long
|
|
157
|
+
enough to carry the algorithm's key size: for HS256 that is 64 hex or 43
|
|
158
|
+
base64 characters. Spaces and punctuation are refused, which also catches
|
|
159
|
+
random secrets from generators that mix in symbols.
|
|
160
|
+
|
|
156
161
|
If that fires on a secret you already use, replace the secret.
|
|
157
162
|
`generateSecret("HS256")` produces one at the algorithm's minimum size.
|
|
158
163
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
**Lacewing is an opinionated JWT library that makes common JWT security mistakes impossible by construction.**
|
|
5
5
|
|
|
6
|
-
Instead of exposing low-level primitives and trusting you to compose them correctly, Lacewing provides secure verification profiles, safe defaults, mandatory claim validation, built-in revocation support, secure cookie helpers, and a curated algorithm set. Everything [RFC 8725 (JWT Best Current Practices)](https://datatracker.ietf.org/doc/html/rfc8725) says an application MUST or SHOULD do is enforced by the type system, enforced at runtime, or impossible to express.
|
|
6
|
+
Instead of exposing low-level primitives and trusting you to compose them correctly, Lacewing provides secure verification profiles, safe defaults, mandatory claim validation, built-in revocation support, secure cookie helpers, and a curated algorithm set. Everything [RFC 8725 (JWT Best Current Practices)](https://datatracker.ietf.org/doc/html/rfc8725) says an application MUST or SHOULD do is enforced by the type system, enforced at runtime, or impossible to express, except where only your application has the facts: keeping two of your own profiles apart (give each kind of token its own `typ`), and choosing a strong HMAC secret (use `generateSecret()`; the entropy check is a heuristic).
|
|
7
|
+
|
|
8
|
+
**The signature maths is not ours, and that shows in the RFC compliance.** Lacewing enforces the *policy* RFC 8725 asks for. The ECDSA and EdDSA signing and verifying, curve point checks, and nonce generation are done by [jose](https://github.com/panva/jose) on top of Node's WebCrypto (OpenSSL). Lacewing does not control or re-check them. For example, ECDSA nonces are whatever Node's OpenSSL build produces (randomised, not RFC 6979 deterministic), and low-level primitive conformance is only as good as your Node version. The compliance suite tests that Lacewing calls these primitives correctly, not the primitives themselves.
|
|
7
9
|
|
|
8
10
|
**Batteries loaded (RFC 8725).** Out of the box:
|
|
9
11
|
|
|
@@ -152,12 +154,18 @@ keys: {
|
|
|
152
154
|
|
|
153
155
|
Selection is exact: the token's `kid` (and its algorithm's key type and curve)
|
|
154
156
|
has to single out one key. Two keys that both match with no `kid` to tell them
|
|
155
|
-
apart is treated as your mistake, not something to guess at.
|
|
157
|
+
apart is treated as your mistake, not something to guess at. The same goes for
|
|
158
|
+
a key with no `alg`: if the profile allows several algorithms that key could
|
|
159
|
+
serve (say `PS256` and `PS512` for one RSA key), it is refused rather than
|
|
160
|
+
used under all of them. Set `alg` on the key. EC and OKP keys are exempt,
|
|
161
|
+
because their curve already names the algorithm.
|
|
156
162
|
|
|
157
163
|
And if your keys live somewhere less ordinary (an HSM, a secrets manager, a
|
|
158
164
|
database), anything with a `getVerificationKey(header)` method is a valid `keys`
|
|
159
165
|
value. That's the escape hatch; the two built-in sources are just the ones
|
|
160
|
-
you'll reach for most.
|
|
166
|
+
you'll reach for most. It is still held to the same rules: the `alg` it returns
|
|
167
|
+
must be the token's, and a raw HMAC secret it returns goes through the same
|
|
168
|
+
strength check as `importKey`.
|
|
161
169
|
|
|
162
170
|
### Sign
|
|
163
171
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* | | access | refresh |
|
|
13
13
|
* |---|---|---|
|
|
14
14
|
* | `typ` | `at+jwt` | `rt+jwt` |
|
|
15
|
-
* | audience | the API | the auth server's token endpoint |
|
|
15
|
+
* | audience | the API | the auth server's token endpoint (your choice, not checked) |
|
|
16
16
|
* | lifetime | minutes (default 10m) | days (default 30d) |
|
|
17
17
|
* | key source | usually a public JWKS | usually a private, server-only key |
|
|
18
18
|
* | revocation | optional | **strongly recommended** |
|
|
@@ -59,8 +59,9 @@ export function accessTokenProfile(options) {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* A refresh-token profile: long-lived
|
|
63
|
-
*
|
|
62
|
+
* A refresh-token profile: long-lived and pinned to `typ: "rt+jwt"`. Give it
|
|
63
|
+
* the *auth server* as its audience, never the API; nothing here can check
|
|
64
|
+
* that for you, because the profile has never seen your API's audience. Pass a `revocation` store -
|
|
64
65
|
* a long-lived token you cannot revoke is a long-lived incident.
|
|
65
66
|
*/
|
|
66
67
|
export function refreshTokenProfile(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-refresh.js","sourceRoot":"","sources":["../../../src/cookbook/access-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,aAAa,EAAuB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AACzC,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAE1C,MAAM,sBAAsB,GAAG,KAAK,CAAC;AACrC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAWtC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC9D,OAAO,aAAa,CAAC;QACpB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,sBAAsB;QAC1D,GAAG,EAAE,gBAAgB;KACrB,CAAC,CAAC;AACJ,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"access-refresh.js","sourceRoot":"","sources":["../../../src/cookbook/access-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,aAAa,EAAuB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AACzC,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAE1C,MAAM,sBAAsB,GAAG,KAAK,CAAC;AACrC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAWtC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC9D,OAAO,aAAa,CAAC;QACpB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,sBAAsB;QAC1D,GAAG,EAAE,gBAAgB;KACrB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA4B;IAC/D,OAAO,aAAa,CAAC;QACpB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,uBAAuB;QAC3D,GAAG,EAAE,iBAAiB;KACtB,CAAC,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc;IAC7B,OAAO,IAAI,OAAO,CAAC,gBAAgB,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe;IAC9B,OAAO,IAAI,OAAO,CAAC,iBAAiB,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/D,CAAC"}
|
package/dist/src/jwks/local.js
CHANGED
|
@@ -11,6 +11,21 @@ import { EntropyCheckFailed, JWKSNoMatchingKey, KeyImportFailed, } from "../util
|
|
|
11
11
|
import { getAlgorithmProperties, isValidAlgorithm } from "../lib/algorithms.js";
|
|
12
12
|
import { decodeBase64url } from "../lib/base64url.js";
|
|
13
13
|
import { validateHMACSecret } from "../lib/entropy.js";
|
|
14
|
+
/**
|
|
15
|
+
* Whether a JWK without an `alg` member could serve more than one of the
|
|
16
|
+
* profile's algorithms. A curve pins EC/OKP keys to one algorithm, but an
|
|
17
|
+
* RSA or `oct` key fits every allowlisted algorithm of its type, and using
|
|
18
|
+
* one key under several algorithms is what §3.1 forbids.
|
|
19
|
+
*/
|
|
20
|
+
function isUnbound(jwk, allowed) {
|
|
21
|
+
if (jwk.alg !== undefined)
|
|
22
|
+
return false;
|
|
23
|
+
const sameFamily = allowed.filter((alg) => {
|
|
24
|
+
const info = getAlgorithmProperties(alg);
|
|
25
|
+
return info.kty === jwk.kty && info.crv === undefined;
|
|
26
|
+
});
|
|
27
|
+
return sameFamily.length > 1;
|
|
28
|
+
}
|
|
14
29
|
function isCandidate(jwk, header) {
|
|
15
30
|
const info = getAlgorithmProperties(header.alg);
|
|
16
31
|
if (jwk.kty !== info.kty)
|
|
@@ -26,11 +41,15 @@ function isCandidate(jwk, header) {
|
|
|
26
41
|
return true;
|
|
27
42
|
}
|
|
28
43
|
/** Shared selection + import used by both local and remote sets. */
|
|
29
|
-
export async function resolveFromJwks(keys, header, options = {}) {
|
|
44
|
+
export async function resolveFromJwks(keys, header, allowed, options = {}) {
|
|
30
45
|
const allowSymmetric = options.allowSymmetric ?? true;
|
|
31
|
-
const
|
|
46
|
+
const matching = keys.filter((jwk) => isCandidate(jwk, header) && (allowSymmetric || jwk.kty !== "oct"));
|
|
47
|
+
const candidates = matching.filter((jwk) => !isUnbound(jwk, allowed));
|
|
32
48
|
if (candidates.length === 0) {
|
|
33
|
-
throw new JWKSNoMatchingKey(
|
|
49
|
+
throw new JWKSNoMatchingKey(matching.length === 0
|
|
50
|
+
? "No key in the JWKS matches this token"
|
|
51
|
+
: "A matching JWKS key has no alg and the profile allows several " +
|
|
52
|
+
"algorithms for its key type; set alg on the key");
|
|
34
53
|
}
|
|
35
54
|
if (candidates.length > 1) {
|
|
36
55
|
throw new JWKSNoMatchingKey("Multiple keys in the JWKS match this token - issue tokens with a kid");
|
|
@@ -78,8 +97,8 @@ export function validateJwksShape(jwks) {
|
|
|
78
97
|
export function createLocalJWKSet(jwks) {
|
|
79
98
|
const keys = validateJwksShape(jwks);
|
|
80
99
|
return {
|
|
81
|
-
getVerificationKey(header) {
|
|
82
|
-
return resolveFromJwks(keys, header);
|
|
100
|
+
getVerificationKey(header, allowedAlgorithms) {
|
|
101
|
+
return resolveFromJwks(keys, header, allowedAlgorithms);
|
|
83
102
|
},
|
|
84
103
|
};
|
|
85
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/jwks/local.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EACN,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,GACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/jwks/local.ts"],"names":[],"mappings":"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"}
|
package/dist/src/jwks/remote.js
CHANGED
|
@@ -165,10 +165,10 @@ export function createRemoteJWKSet(url, options = {}) {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
return {
|
|
168
|
-
async getVerificationKey(header) {
|
|
168
|
+
async getVerificationKey(header, allowedAlgorithms) {
|
|
169
169
|
await ensureFresh();
|
|
170
170
|
try {
|
|
171
|
-
return await resolveFromJwks(cachedKeys, header, {
|
|
171
|
+
return await resolveFromJwks(cachedKeys, header, allowedAlgorithms, {
|
|
172
172
|
allowSymmetric: false,
|
|
173
173
|
});
|
|
174
174
|
}
|
|
@@ -180,7 +180,7 @@ export function createRemoteJWKSet(url, options = {}) {
|
|
|
180
180
|
if (!canRetry)
|
|
181
181
|
throw error;
|
|
182
182
|
await refresh();
|
|
183
|
-
return resolveFromJwks(cachedKeys, header, {
|
|
183
|
+
return resolveFromJwks(cachedKeys, header, allowedAlgorithms, {
|
|
184
184
|
allowSymmetric: false,
|
|
185
185
|
});
|
|
186
186
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../../src/jwks/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../../src/jwks/remote.ts"],"names":[],"mappings":"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"}
|
package/dist/src/jwt/verify.js
CHANGED
|
@@ -21,6 +21,8 @@ import { decodeUTF8 } from "../lib/utf8.js";
|
|
|
21
21
|
import { parseJsonObject } from "../lib/json.js";
|
|
22
22
|
import { validateHeader } from "../lib/headers.js";
|
|
23
23
|
import { validateClaims } from "../lib/claims.js";
|
|
24
|
+
import { getAlgorithmProperties } from "../lib/algorithms.js";
|
|
25
|
+
import { validateHMACSecret } from "../lib/entropy.js";
|
|
24
26
|
import { buildRevocationContext } from "../revocation/store.js";
|
|
25
27
|
import { isLacewingKey, } from "../types.js";
|
|
26
28
|
// Bounded before any parsing so garbage can't allocate unboundedly.
|
|
@@ -35,7 +37,17 @@ async function resolveKey(profile, header) {
|
|
|
35
37
|
}
|
|
36
38
|
return { alg: header.alg, key: profile.keys.key };
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
// A custom source is held to the same binding as the built-in ones: the
|
|
41
|
+
// algorithm it resolved must be the token's, and a raw HMAC secret goes
|
|
42
|
+
// through the same strength check as `importKey` (§3.1, §3.5).
|
|
43
|
+
const resolved = await profile.keys.getVerificationKey(header, profile.alg);
|
|
44
|
+
if (resolved.alg !== header.alg) {
|
|
45
|
+
throw new AlgorithmNotAllowed("Token algorithm does not match the key source's resolved algorithm");
|
|
46
|
+
}
|
|
47
|
+
if (resolved.key instanceof Uint8Array && getAlgorithmProperties(header.alg).kty === "oct") {
|
|
48
|
+
validateHMACSecret(resolved.key, header.alg);
|
|
49
|
+
}
|
|
50
|
+
return resolved;
|
|
39
51
|
}
|
|
40
52
|
/**
|
|
41
53
|
* Verify a token against a profile. The returned {@link VerifiedJwt} is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/jwt/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EACN,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,YAAY,EACZ,qBAAqB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EACN,aAAa,GAMb,MAAM,aAAa,CAAC;AAErB,oEAAoE;AACpE,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B,SAAS,gBAAgB,CAAC,KAAiB,EAAE,IAAY;IACxD,OAAO,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,KAAK,UAAU,UAAU,CACxB,OAA2B,EAC3B,MAAiB;IAEjB,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,IAAK,OAAO,CAAC,IAAI,CAAC,SAAoB,KAAM,MAAM,CAAC,GAAc,EAAE,CAAC;YACnE,MAAM,IAAI,mBAAmB,CAC5B,kDAAkD,CAClD,CAAC;QACH,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACnD,CAAC;IACD,
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/jwt/verify.ts"],"names":[],"mappings":"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"}
|
package/dist/src/lib/entropy.js
CHANGED
|
@@ -15,8 +15,6 @@ const COMMON_WORDS = [
|
|
|
15
15
|
"secret",
|
|
16
16
|
"letmein",
|
|
17
17
|
"qwerty",
|
|
18
|
-
"123456",
|
|
19
|
-
"abcdef",
|
|
20
18
|
"changeme",
|
|
21
19
|
"default",
|
|
22
20
|
];
|
|
@@ -32,10 +30,79 @@ function shannonBitsPerByte(bytes) {
|
|
|
32
30
|
}
|
|
33
31
|
return bits;
|
|
34
32
|
}
|
|
33
|
+
const HEX = /^[0-9a-f]+$/i;
|
|
34
|
+
const BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
35
|
+
const BASE64URL = /^[A-Za-z0-9_-]+$/;
|
|
36
|
+
// Lowercased QWERTY rows, for spotting keyboard walks like "qazwsx".
|
|
37
|
+
const KEYBOARD_ROWS = ["1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"];
|
|
38
|
+
const KEY_POSITIONS = new Map();
|
|
39
|
+
KEYBOARD_ROWS.forEach((row, r) => {
|
|
40
|
+
[...row].forEach((key, c) => KEY_POSITIONS.set(key, [r, c]));
|
|
41
|
+
});
|
|
42
|
+
function areKeyboardNeighbours(a, b) {
|
|
43
|
+
const pa = KEY_POSITIONS.get(a);
|
|
44
|
+
const pb = KEY_POSITIONS.get(b);
|
|
45
|
+
if (pa === undefined || pb === undefined)
|
|
46
|
+
return false;
|
|
47
|
+
const rows = Math.abs(pa[0] - pb[0]);
|
|
48
|
+
const cols = Math.abs(pa[1] - pb[1]);
|
|
49
|
+
return rows + cols > 0 && rows <= 1 && cols <= 1;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Longest run of consecutive ascending characters ("123456", "abcdef"),
|
|
53
|
+
* counted on the lowercased text.
|
|
54
|
+
*/
|
|
55
|
+
function longestAscendingRun(text) {
|
|
56
|
+
let longest = 1;
|
|
57
|
+
let run = 1;
|
|
58
|
+
for (let i = 1; i < text.length; i++) {
|
|
59
|
+
run = text.charCodeAt(i) === text.charCodeAt(i - 1) + 1 ? run + 1 : 1;
|
|
60
|
+
longest = Math.max(longest, run);
|
|
61
|
+
}
|
|
62
|
+
return longest;
|
|
63
|
+
}
|
|
64
|
+
/** Whether the text is one shorter chunk repeated ("deadbeefdeadbeef..."). */
|
|
65
|
+
function isPeriodic(text) {
|
|
66
|
+
for (let period = 1; period <= text.length / 2; period++) {
|
|
67
|
+
if (text.length % period !== 0)
|
|
68
|
+
continue;
|
|
69
|
+
if (text.slice(period) === text.slice(0, -period))
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/** Share of adjacent character pairs that sit next to each other on a keyboard. */
|
|
75
|
+
function keyboardWalkRatio(text) {
|
|
76
|
+
let neighbours = 0;
|
|
77
|
+
for (let i = 1; i < text.length; i++) {
|
|
78
|
+
if (areKeyboardNeighbours(text[i - 1], text[i]))
|
|
79
|
+
neighbours += 1;
|
|
80
|
+
}
|
|
81
|
+
return neighbours / Math.max(1, text.length - 1);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Bits of key material a printable secret can carry: 4 per character for
|
|
85
|
+
* hex, 6 for base64 or base64url. Anything else is not an encoded random key,
|
|
86
|
+
* so it carries none we can vouch for.
|
|
87
|
+
*/
|
|
88
|
+
export function encodedSecretBits(text) {
|
|
89
|
+
if (HEX.test(text))
|
|
90
|
+
return text.length * 4;
|
|
91
|
+
const unpadded = text.replace(/=+$/, "");
|
|
92
|
+
if (BASE64.test(text) || BASE64URL.test(text))
|
|
93
|
+
return unpadded.length * 6;
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
35
96
|
/**
|
|
36
97
|
* Heuristic: does this byte sequence look like a human-chosen password
|
|
37
98
|
* rather than a random key? Only printable-ASCII inputs are suspected -
|
|
38
99
|
* raw random bytes virtually never stay inside that range.
|
|
100
|
+
*
|
|
101
|
+
* A printable secret must look like an encoded random key: hex, base64 or
|
|
102
|
+
* base64url, with no common word, no keyboard walk, and the character spread
|
|
103
|
+
* random output has. Spaces and punctuation fail outright, which also turns
|
|
104
|
+
* away random secrets from generators that add symbols; encode random bytes
|
|
105
|
+
* instead. A passphrase made only of letters and digits can still pass.
|
|
39
106
|
*/
|
|
40
107
|
export function isPasswordLike(bytes) {
|
|
41
108
|
const printableAscii = bytes.every((b) => b >= 0x20 && b <= 0x7e);
|
|
@@ -48,18 +115,33 @@ export function isPasswordLike(bytes) {
|
|
|
48
115
|
for (let i = 0; i < bytes.length; i += 4096) {
|
|
49
116
|
text += String.fromCharCode(...bytes.subarray(i, i + 4096));
|
|
50
117
|
}
|
|
51
|
-
text
|
|
52
|
-
if (COMMON_WORDS.some((word) => text.includes(word))) {
|
|
118
|
+
if (encodedSecretBits(text) === 0) {
|
|
53
119
|
return true;
|
|
54
120
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
121
|
+
const lower = text.toLowerCase();
|
|
122
|
+
const hex = HEX.test(text);
|
|
123
|
+
if (COMMON_WORDS.some((word) => lower.includes(word))) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// Every threshold below was set against millions of random keys; see
|
|
127
|
+
// the random-key regression test in tests/unit/lib/entropy.test.ts.
|
|
128
|
+
if (isPeriodic(lower) || longestAscendingRun(lower) >= (hex ? 10 : 8)) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
if (keyboardWalkRatio(lower) > 0.6) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
// Random hex sits near 3.8 bits/byte (its ceiling is 4) and random base64
|
|
135
|
+
// near 4.6, so each alphabet gets its own floor.
|
|
136
|
+
return shannonBitsPerByte(bytes) < (hex ? 3 : 3.5);
|
|
58
137
|
}
|
|
59
138
|
/**
|
|
60
139
|
* Validate an HMAC secret for the given HS* algorithm.
|
|
61
140
|
* Throws {@link EntropyCheckFailed} when the secret is too short or
|
|
62
141
|
* looks like a password.
|
|
142
|
+
*
|
|
143
|
+
* A printable secret is measured by what its encoding carries, not its byte
|
|
144
|
+
* count: 64 hex characters are 64 bytes but only 256 bits of key.
|
|
63
145
|
*/
|
|
64
146
|
export function validateHMACSecret(secret, algorithmName) {
|
|
65
147
|
const { minKeyBits } = getAlgorithmProperties(algorithmName);
|
|
@@ -72,5 +154,10 @@ export function validateHMACSecret(secret, algorithmName) {
|
|
|
72
154
|
throw new EntropyCheckFailed("HMAC secret looks like a human-chosen password; use " +
|
|
73
155
|
"cryptographically random bytes (e.g. generateSecret())");
|
|
74
156
|
}
|
|
157
|
+
const printable = secret.every((b) => b >= 0x20 && b <= 0x7e);
|
|
158
|
+
if (printable && encodedSecretBits(new TextDecoder().decode(secret)) < minKeyBits) {
|
|
159
|
+
throw new EntropyCheckFailed(`HMAC secret for ${algorithmName} must encode at least ${minKeyBits} bits; ` +
|
|
160
|
+
`that is ${Math.ceil(minKeyBits / 4)} hex or ${Math.ceil(minKeyBits / 6)} base64 characters`);
|
|
161
|
+
}
|
|
75
162
|
}
|
|
76
163
|
//# sourceMappingURL=entropy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entropy.js","sourceRoot":"","sources":["../../../src/lib/entropy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,6DAA6D;AAC7D,MAAM,YAAY,GAAG;IACpB,UAAU;IACV,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,
|
|
1
|
+
{"version":3,"file":"entropy.js","sourceRoot":"","sources":["../../../src/lib/entropy.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* | | access | refresh |
|
|
13
13
|
* |---|---|---|
|
|
14
14
|
* | `typ` | `at+jwt` | `rt+jwt` |
|
|
15
|
-
* | audience | the API | the auth server's token endpoint |
|
|
15
|
+
* | audience | the API | the auth server's token endpoint (your choice, not checked) |
|
|
16
16
|
* | lifetime | minutes (default 10m) | days (default 30d) |
|
|
17
17
|
* | key source | usually a public JWKS | usually a private, server-only key |
|
|
18
18
|
* | revocation | optional | **strongly recommended** |
|
|
@@ -60,8 +60,9 @@ export type TokenProfileOptions = Omit<ProfileOptions, "typ" | "maxTokenAge"> &
|
|
|
60
60
|
*/
|
|
61
61
|
export declare function accessTokenProfile(options: TokenProfileOptions): ExpectedJwtProfile;
|
|
62
62
|
/**
|
|
63
|
-
* A refresh-token profile: long-lived
|
|
64
|
-
*
|
|
63
|
+
* A refresh-token profile: long-lived and pinned to `typ: "rt+jwt"`. Give it
|
|
64
|
+
* the *auth server* as its audience, never the API; nothing here can check
|
|
65
|
+
* that for you, because the profile has never seen your API's audience. Pass a `revocation` store -
|
|
65
66
|
* a long-lived token you cannot revoke is a long-lived incident.
|
|
66
67
|
*/
|
|
67
68
|
export declare function refreshTokenProfile(options: TokenProfileOptions): ExpectedJwtProfile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-refresh.d.ts","sourceRoot":"","sources":["../../../../src/cookbook/access-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAK1C;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,aAAa,CAAC,GAAG;IAC/E,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAMnF;AAED
|
|
1
|
+
{"version":3,"file":"access-refresh.d.ts","sourceRoot":"","sources":["../../../../src/cookbook/access-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAK1C;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,aAAa,CAAC,GAAG;IAC/E,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAMnF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAMpF;AAED,gFAAgF;AAChF,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* never candidates. `kid` values arriving here have already been
|
|
7
7
|
* sanitized by header validation (§3.10).
|
|
8
8
|
*/
|
|
9
|
-
import type { JwtHeader, KeySource, ResolvedVerificationKey, StaticJWK, StaticJWKS } from "../types.js";
|
|
9
|
+
import type { JwtHeader, KeySource, ResolvedVerificationKey, StaticJWK, StaticJWKS, ValidAlg } from "../types.js";
|
|
10
10
|
export interface ResolveFromJwksOptions {
|
|
11
11
|
/**
|
|
12
12
|
* Whether symmetric (`oct`) entries may be used. False for remote sets: a
|
|
@@ -16,7 +16,7 @@ export interface ResolveFromJwksOptions {
|
|
|
16
16
|
allowSymmetric?: boolean;
|
|
17
17
|
}
|
|
18
18
|
/** Shared selection + import used by both local and remote sets. */
|
|
19
|
-
export declare function resolveFromJwks(keys: readonly StaticJWK[], header: JwtHeader, options?: ResolveFromJwksOptions): Promise<ResolvedVerificationKey>;
|
|
19
|
+
export declare function resolveFromJwks(keys: readonly StaticJWK[], header: JwtHeader, allowed: readonly ValidAlg[], options?: ResolveFromJwksOptions): Promise<ResolvedVerificationKey>;
|
|
20
20
|
/** Validate the developer-supplied JWKS document shape (config error -> TypeError). */
|
|
21
21
|
export declare function validateJwksShape(jwks: unknown): StaticJWK[];
|
|
22
22
|
/** Create a {@link KeySource} backed by a static JWKS document. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../../src/jwks/local.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,KAAK,EACX,SAAS,EACT,SAAS,EACT,uBAAuB,EACvB,SAAS,EACT,UAAU,EACV,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../../src/jwks/local.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,KAAK,EACX,SAAS,EACT,SAAS,EACT,uBAAuB,EACvB,SAAS,EACT,UAAU,EACV,QAAQ,EACR,MAAM,aAAa,CAAC;AA2BrB,MAAM,WAAW,sBAAsB;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CACpC,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,OAAO,GAAE,sBAA2B,GAClC,OAAO,CAAC,uBAAuB,CAAC,CAwClC;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,CAsB5D;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAU7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../../src/jwks/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAEX,SAAS,
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../../src/jwks/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAEX,SAAS,EAIT,MAAM,aAAa,CAAC;AASrB,MAAM,WAAW,mBAAmB;IACnC,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAwDD,wEAAwE;AACxE,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,GAAG,GAAG,MAAM,EACjB,OAAO,GAAE,mBAAwB,GAC/B,SAAS,CAyHX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../src/jwt/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../src/jwt/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAkBH,OAAO,EAEN,KAAK,kBAAkB,EAIvB,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAoCrB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,SAAS,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CA+DtB"}
|
|
@@ -6,16 +6,31 @@
|
|
|
6
6
|
* 2. A heuristic that rejects password-looking strings - the classic
|
|
7
7
|
* `secret: "my-secret"` misuse - even when they are long enough.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* Bits of key material a printable secret can carry: 4 per character for
|
|
11
|
+
* hex, 6 for base64 or base64url. Anything else is not an encoded random key,
|
|
12
|
+
* so it carries none we can vouch for.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodedSecretBits(text: string): number;
|
|
9
15
|
/**
|
|
10
16
|
* Heuristic: does this byte sequence look like a human-chosen password
|
|
11
17
|
* rather than a random key? Only printable-ASCII inputs are suspected -
|
|
12
18
|
* raw random bytes virtually never stay inside that range.
|
|
19
|
+
*
|
|
20
|
+
* A printable secret must look like an encoded random key: hex, base64 or
|
|
21
|
+
* base64url, with no common word, no keyboard walk, and the character spread
|
|
22
|
+
* random output has. Spaces and punctuation fail outright, which also turns
|
|
23
|
+
* away random secrets from generators that add symbols; encode random bytes
|
|
24
|
+
* instead. A passphrase made only of letters and digits can still pass.
|
|
13
25
|
*/
|
|
14
26
|
export declare function isPasswordLike(bytes: Uint8Array): boolean;
|
|
15
27
|
/**
|
|
16
28
|
* Validate an HMAC secret for the given HS* algorithm.
|
|
17
29
|
* Throws {@link EntropyCheckFailed} when the secret is too short or
|
|
18
30
|
* looks like a password.
|
|
31
|
+
*
|
|
32
|
+
* A printable secret is measured by what its encoding carries, not its byte
|
|
33
|
+
* count: 64 hex characters are 64 bytes but only 256 bits of key.
|
|
19
34
|
*/
|
|
20
35
|
export declare function validateHMACSecret(secret: Uint8Array, algorithmName: string): void;
|
|
21
36
|
//# sourceMappingURL=entropy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../../../src/lib/entropy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../../../src/lib/entropy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiFH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CA8BzD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAsBlF"}
|
package/package.json
CHANGED