@rapidrest/core 1.14.0 → 2.0.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/dist/lib/AlertUtils.js +71 -56
- package/dist/lib/AlertUtils.js.map +1 -1
- package/dist/lib/ApiError.js +8 -1
- package/dist/lib/ApiError.js.map +1 -1
- package/dist/lib/CacheUtils.js +23 -0
- package/dist/lib/CacheUtils.js.map +1 -0
- package/dist/lib/ClassLoader.js +48 -44
- package/dist/lib/ClassLoader.js.map +1 -1
- package/dist/lib/FileUtils.js +133 -60
- package/dist/lib/FileUtils.js.map +1 -1
- package/dist/lib/JWTUtils.js +250 -145
- package/dist/lib/JWTUtils.js.map +1 -1
- package/dist/lib/Logger.js +39 -7
- package/dist/lib/Logger.js.map +1 -1
- package/dist/lib/MemoryStore.js +8 -6
- package/dist/lib/MemoryStore.js.map +1 -1
- package/dist/lib/MessagingUtils.js +71 -35
- package/dist/lib/MessagingUtils.js.map +1 -1
- package/dist/lib/NotificationsUtils.js +60 -8
- package/dist/lib/NotificationsUtils.js.map +1 -1
- package/dist/lib/OASUtils.js +67 -18
- package/dist/lib/OASUtils.js.map +1 -1
- package/dist/lib/ObjectFactory.js +151 -63
- package/dist/lib/ObjectFactory.js.map +1 -1
- package/dist/lib/ObjectUtils.js +48 -7
- package/dist/lib/ObjectUtils.js.map +1 -1
- package/dist/lib/StringUtils.js +55 -21
- package/dist/lib/StringUtils.js.map +1 -1
- package/dist/lib/TelemetryUtils.js +41 -5
- package/dist/lib/TelemetryUtils.js.map +1 -1
- package/dist/lib/UserUtils.js +5 -6
- package/dist/lib/UserUtils.js.map +1 -1
- package/dist/lib/ValidationUtils.js +16 -4
- package/dist/lib/ValidationUtils.js.map +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/threads/ThreadPool.js +198 -58
- package/dist/lib/threads/ThreadPool.js.map +1 -1
- package/dist/types/AlertUtils.d.ts +4 -0
- package/dist/types/CacheUtils.d.ts +14 -0
- package/dist/types/ClassLoader.d.ts +10 -0
- package/dist/types/FileUtils.d.ts +23 -7
- package/dist/types/JWTUtils.d.ts +88 -18
- package/dist/types/MessagingUtils.d.ts +7 -1
- package/dist/types/NotificationsUtils.d.ts +30 -0
- package/dist/types/ObjectFactory.d.ts +25 -1
- package/dist/types/ObjectUtils.d.ts +14 -0
- package/dist/types/StringUtils.d.ts +8 -0
- package/dist/types/TelemetryUtils.d.ts +19 -1
- package/dist/types/ValidationUtils.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/threads/ThreadPool.d.ts +34 -2
- package/package.json +1 -1
package/dist/lib/JWTUtils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
///////////////////////////////////////////////////////////////////////////////
|
|
2
2
|
// Copyright (C) 2020-2026 Jean-Philippe Steinmetz
|
|
3
3
|
///////////////////////////////////////////////////////////////////////////////
|
|
4
|
-
import crypto from "crypto";
|
|
4
|
+
import crypto, { KeyObject } from "crypto";
|
|
5
5
|
import jwt from "jsonwebtoken";
|
|
6
6
|
import zlib from "zlib";
|
|
7
7
|
/**
|
|
@@ -19,78 +19,161 @@ export var JWTUtilsCompressionMethods;
|
|
|
19
19
|
*/
|
|
20
20
|
export class JWTUtils {
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* Returns `true` if `secret` is a form that is only ever usable as a genuine HMAC secret - a plain
|
|
23
|
+
* string/Buffer that isn't PEM-encoded, or a `KeyObject` of type `"secret"`. Anything else (a PEM
|
|
24
|
+
* string/Buffer, an asymmetric `KeyObject`, a `{ key, passphrase }` wrapper, a `GetPublicKeyOrSecret`
|
|
25
|
+
* callback, a JWK-shaped object, etc.) is *not* considered safe, since it may resolve to a non-secret
|
|
26
|
+
* (public) value that an attacker could use to forge an HS256/384/512 token.
|
|
27
|
+
*/
|
|
28
|
+
static isKnownSafeHmacSecret(secret) {
|
|
29
|
+
const pemPattern = /-----BEGIN [A-Z ]*(PRIVATE|PUBLIC) KEY-----/;
|
|
30
|
+
if (typeof secret === "string") {
|
|
31
|
+
return !pemPattern.test(secret);
|
|
32
|
+
}
|
|
33
|
+
// `fs.readFileSync()` - the idiomatic way to load a key file - returns a Buffer, not a string, so both
|
|
34
|
+
// representations must be checked here.
|
|
35
|
+
if (Buffer.isBuffer(secret)) {
|
|
36
|
+
return !pemPattern.test(secret.toString("utf8"));
|
|
37
|
+
}
|
|
38
|
+
if (secret instanceof KeyObject) {
|
|
39
|
+
return secret.type === "secret";
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Throws unless `config.secret` is a known-safe plain HMAC secret. Any other secret shape is treated
|
|
45
|
+
* conservatively as potentially asymmetric (fail closed, rather than only matching a fixed allowlist of
|
|
46
|
+
* asymmetric shapes seen so far) and requires `config.options.algorithms` to be explicitly set to a list
|
|
47
|
+
* that does not itself include an HMAC algorithm. Without this, signing/verifying with e.g. an RSA key
|
|
48
|
+
* while leaving `algorithms` unset - or restricting it to `["RS256", "HS256"]` - opens the door to
|
|
49
|
+
* algorithm-confusion attacks: an attacker holding only the public half of the key pair can forge a token
|
|
50
|
+
* by signing it with HS256 using that public value as the HMAC secret.
|
|
26
51
|
*
|
|
27
52
|
* @param config The JWT configuration to validate.
|
|
28
53
|
*/
|
|
29
54
|
static assertSafeAlgorithm(config) {
|
|
30
55
|
const secret = config.secret;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
if (looksAsymmetric && (!config.options?.algorithms || config.options.algorithms.length === 0)) {
|
|
56
|
+
if (JWTUtils.isKnownSafeHmacSecret(secret)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const algorithms = config.options?.algorithms;
|
|
60
|
+
if (!algorithms || algorithms.length === 0) {
|
|
37
61
|
throw new Error("config.secret appears to be an asymmetric key. config.options.algorithms must be explicitly set " +
|
|
38
62
|
"(e.g. ['RS256']) to prevent algorithm-confusion attacks.");
|
|
39
63
|
}
|
|
64
|
+
if (algorithms.some((alg) => JWTUtils.HMAC_ALGORITHMS.has(alg))) {
|
|
65
|
+
throw new Error("config.options.algorithms includes an HMAC algorithm (HS256/HS384/HS512) alongside a " +
|
|
66
|
+
"non-HMAC secret. This would allow an attacker holding the public half of the key to forge " +
|
|
67
|
+
"tokens via algorithm confusion. Remove HMAC algorithms from config.options.algorithms.");
|
|
68
|
+
}
|
|
40
69
|
}
|
|
41
70
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
71
|
+
* Returns the key length, in bytes, required by `algorithm` (e.g. 32 for `aes-256-cbc`, 24 for
|
|
72
|
+
* `aes-192-cbc`), so the scrypt-derived key `deriveKey`/`deriveKeySync` produce always matches whatever
|
|
73
|
+
* cipher `passwordOptions.algorithm` actually names, instead of a length hard-coded for one specific
|
|
74
|
+
* algorithm. Throws a clear error for an algorithm Node's `crypto` module doesn't recognize, rather than
|
|
75
|
+
* letting `createCipheriv`/`createDecipheriv` fail later with an opaque "Invalid key length".
|
|
76
|
+
*/
|
|
77
|
+
static resolveKeyLength(algorithm) {
|
|
78
|
+
const info = crypto.getCipherInfo(algorithm);
|
|
79
|
+
if (!info?.keyLength) {
|
|
80
|
+
throw new Error(`Unknown or unsupported cipher algorithm: "${algorithm}".`);
|
|
81
|
+
}
|
|
82
|
+
return info.keyLength;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Derives a symmetric encryption key from `password`/`salt` for use with `algorithm`.
|
|
86
|
+
*/
|
|
87
|
+
static deriveKey(password, salt, algorithm) {
|
|
88
|
+
const keyLength = JWTUtils.resolveKeyLength(algorithm);
|
|
89
|
+
return new Promise((resolve, reject) => crypto.scrypt(password, salt, keyLength, (err, key) => (err ? reject(err) : resolve(key))));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Synchronous counterpart to `deriveKey()`. **Blocks the event loop** for the duration of the scrypt
|
|
93
|
+
* derivation (deliberately CPU-expensive, typically tens of milliseconds) - `createTokenSync`/
|
|
94
|
+
* `decodeTokenSync` should therefore be avoided on a request-handling path when password-based payload
|
|
95
|
+
* encryption is configured; prefer `createToken`/`decodeToken` there.
|
|
96
|
+
*/
|
|
97
|
+
static deriveKeySync(password, salt, algorithm) {
|
|
98
|
+
return crypto.scryptSync(password, salt, JWTUtils.resolveKeyLength(algorithm));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Encrypts `plaintext` for `publicKey` using hybrid encryption: `plaintext` is encrypted with a fresh
|
|
102
|
+
* AES-256-GCM key, which is itself wrapped with RSA. This avoids `crypto.publicEncrypt`'s fixed plaintext-size
|
|
103
|
+
* limit (e.g. ~214 bytes for a 2048-bit key with OAEP padding), which a raw JSON user profile easily exceeds.
|
|
44
104
|
*
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
105
|
+
* @param publicKey The RSA public key to wrap the AES key with.
|
|
106
|
+
* @param plaintext The data to encrypt.
|
|
107
|
+
* @returns The encrypted data, encoded as `<wrapped-key>.<iv>.<authTag>.<ciphertext>`, all base64.
|
|
108
|
+
*/
|
|
109
|
+
static hybridEncrypt(publicKey, plaintext) {
|
|
110
|
+
const aesKey = crypto.randomBytes(32);
|
|
111
|
+
const iv = crypto.randomBytes(12);
|
|
112
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", aesKey, iv);
|
|
113
|
+
let ciphertext = cipher.update(plaintext, "utf8", "base64");
|
|
114
|
+
ciphertext += cipher.final("base64");
|
|
115
|
+
const authTag = cipher.getAuthTag();
|
|
116
|
+
const wrappedKey = crypto.publicEncrypt(publicKey, aesKey);
|
|
117
|
+
return [wrappedKey.toString("base64"), iv.toString("base64"), authTag.toString("base64"), ciphertext].join(".");
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Returns the base64-encoded authentication tag for `cipher` if it's an AEAD cipher, otherwise `""`. Rather
|
|
121
|
+
* than pattern-matching the algorithm name (which only recognizes a fixed list of known AEAD naming
|
|
122
|
+
* conventions), this asks the cipher itself via `getAuthTag()`, which throws for any non-AEAD cipher - so
|
|
123
|
+
* any AEAD cipher/alias supported by the current Node/OpenSSL build is handled correctly, including ones
|
|
124
|
+
* not known when this was last updated.
|
|
47
125
|
*/
|
|
48
|
-
static
|
|
49
|
-
|
|
126
|
+
static getAuthTagIfAEAD(cipher) {
|
|
127
|
+
try {
|
|
128
|
+
return cipher.getAuthTag().toString("base64");
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return "";
|
|
132
|
+
}
|
|
50
133
|
}
|
|
51
134
|
/**
|
|
52
|
-
*
|
|
53
|
-
* user.
|
|
135
|
+
* Decrypts data produced by `hybridEncrypt`.
|
|
54
136
|
*
|
|
55
|
-
* @param
|
|
56
|
-
* @param
|
|
137
|
+
* @param privateKey The RSA private key to unwrap the AES key with.
|
|
138
|
+
* @param encoded The encrypted data, as produced by `hybridEncrypt`.
|
|
57
139
|
*/
|
|
58
|
-
static
|
|
59
|
-
|
|
140
|
+
static hybridDecrypt(privateKey, encoded) {
|
|
141
|
+
const parts = encoded.split(".");
|
|
142
|
+
// Mirrors the length check `finishPasswordDecryption`'s caller performs for the password-based format:
|
|
143
|
+
// without it, a malformed `profile` (e.g. from an outdated/different format) throws an untyped
|
|
144
|
+
// `TypeError` out of `Buffer.from(undefined, ...)` below instead of a clear, identifiable error.
|
|
145
|
+
if (parts.length !== 4) {
|
|
146
|
+
throw new Error("Encrypted profile uses an unrecognized or outdated format and cannot be decoded.");
|
|
147
|
+
}
|
|
148
|
+
const [wrappedKeyB64, ivB64, authTagB64, ciphertext] = parts;
|
|
149
|
+
const aesKey = crypto.privateDecrypt(privateKey, Buffer.from(wrappedKeyB64, "base64"));
|
|
150
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
151
|
+
const authTag = Buffer.from(authTagB64, "base64");
|
|
152
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", aesKey, iv);
|
|
153
|
+
decipher.setAuthTag(authTag);
|
|
154
|
+
let decrypted = decipher.update(ciphertext, "base64", "utf8");
|
|
155
|
+
decrypted += decipher.final("utf8");
|
|
156
|
+
return decrypted;
|
|
60
157
|
}
|
|
61
|
-
|
|
62
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Builds the signable payload shared by `createToken`/`createTokenSync`: validates `config`/`user`, spreads
|
|
160
|
+
* `data`, compresses the profile if requested, and - for public-key encryption only, which has no async
|
|
161
|
+
* dependency - encrypts it. Password-based encryption is left for the caller to finish via
|
|
162
|
+
* `finishPasswordEncryption()`, since deriving the key is the one step that differs between the sync and
|
|
163
|
+
* async entry points.
|
|
164
|
+
*/
|
|
165
|
+
static preparePayload(config, user, data) {
|
|
63
166
|
if (!config.secret) {
|
|
64
167
|
throw new Error("Invalid configuration provided.");
|
|
65
168
|
}
|
|
66
|
-
// Validate the user object
|
|
67
169
|
if (!user || !user.uid) {
|
|
68
170
|
throw new Error("Invalid or null user object provided.");
|
|
69
171
|
}
|
|
70
172
|
// `data` is spread before `profile` so that a `profile` key present in caller-supplied `data` can never
|
|
71
173
|
// silently override the authoritative, server-derived user profile before signing.
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
const payloadOptions = config.payload;
|
|
76
|
-
if (payloadOptions.public_key) {
|
|
77
|
-
const keyOptions = payloadOptions;
|
|
78
|
-
const encrypted = crypto.publicEncrypt(keyOptions.public_key, Buffer.from(payload.profile));
|
|
79
|
-
payload.profile = encrypted.toString("base64");
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
const pwOtions = payloadOptions;
|
|
83
|
-
const iv = Buffer.from(pwOtions.iv);
|
|
84
|
-
const salt = crypto.randomBytes(16);
|
|
85
|
-
const key = await JWTUtils.deriveKey(pwOtions.password, salt);
|
|
86
|
-
const cipher = crypto.createCipheriv(pwOtions.algorithm, key, iv);
|
|
87
|
-
let encrypted = cipher.update(payload.profile, "utf8", "base64");
|
|
88
|
-
encrypted += cipher.final("base64");
|
|
89
|
-
payload.profile = salt.toString("base64") + ":" + encrypted;
|
|
90
|
-
}
|
|
91
|
-
payload.encryption = true;
|
|
92
|
-
}
|
|
93
|
-
// Compress the profile if desired
|
|
174
|
+
const payload = { ...data, profile: JSON.stringify(user) };
|
|
175
|
+
// Compress the profile if desired. Done *before* encryption so encryption (and, for RSA, its fixed
|
|
176
|
+
// plaintext-size limit) operates on the smaller compressed representation rather than the raw JSON.
|
|
94
177
|
if (config.payload && config.payload.compress) {
|
|
95
178
|
if (config.payload.compress === JWTUtilsCompressionMethods.ZLIB) {
|
|
96
179
|
const buf = Buffer.from(payload.profile, "utf-8");
|
|
@@ -98,94 +181,124 @@ export class JWTUtils {
|
|
|
98
181
|
payload.compression = "zlib";
|
|
99
182
|
}
|
|
100
183
|
}
|
|
101
|
-
|
|
102
|
-
return jwt.sign(payload, config.secret, config.options);
|
|
103
|
-
}
|
|
104
|
-
static createTokenSync(config, user, data) {
|
|
105
|
-
// Validate the required config options
|
|
106
|
-
if (!config.secret) {
|
|
107
|
-
throw new Error("Invalid configuration provided.");
|
|
108
|
-
}
|
|
109
|
-
// Validate the user object
|
|
110
|
-
if (!user || !user.uid) {
|
|
111
|
-
throw new Error("Invalid or null user object provided.");
|
|
112
|
-
}
|
|
113
|
-
// `data` is spread before `profile` so that a `profile` key present in caller-supplied `data` can never
|
|
114
|
-
// silently override the authoritative, server-derived user profile before signing.
|
|
115
|
-
let payload = { ...data, profile: JSON.stringify(user) };
|
|
116
|
-
// Encrypt the profile if desired
|
|
184
|
+
let passwordOptions;
|
|
117
185
|
if (config.payload && config.payload.encrypt) {
|
|
118
186
|
const payloadOptions = config.payload;
|
|
119
187
|
if (payloadOptions.public_key) {
|
|
120
188
|
const keyOptions = payloadOptions;
|
|
121
|
-
|
|
122
|
-
payload.
|
|
189
|
+
payload.profile = JWTUtils.hybridEncrypt(keyOptions.public_key, payload.profile);
|
|
190
|
+
payload.encryption = true;
|
|
123
191
|
}
|
|
124
192
|
else {
|
|
125
|
-
|
|
126
|
-
const iv = Buffer.from(pwOtions.iv);
|
|
127
|
-
const salt = crypto.randomBytes(16);
|
|
128
|
-
const key = JWTUtils.deriveKeySync(pwOtions.password, salt);
|
|
129
|
-
const cipher = crypto.createCipheriv(pwOtions.algorithm, key, iv);
|
|
130
|
-
let encrypted = cipher.update(payload.profile, "utf8", "base64");
|
|
131
|
-
encrypted += cipher.final("base64");
|
|
132
|
-
payload.profile = salt.toString("base64") + ":" + encrypted;
|
|
193
|
+
passwordOptions = payloadOptions;
|
|
133
194
|
}
|
|
134
|
-
payload.encryption = true;
|
|
135
195
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
196
|
+
return { payload, passwordOptions };
|
|
197
|
+
}
|
|
198
|
+
/** Finishes password-based payload encryption once `key` has been derived (sync or async). */
|
|
199
|
+
static finishPasswordEncryption(payload, passwordOptions, key, salt) {
|
|
200
|
+
const iv = Buffer.from(passwordOptions.iv);
|
|
201
|
+
const cipher = crypto.createCipheriv(passwordOptions.algorithm, key, iv);
|
|
202
|
+
let encrypted = cipher.update(payload.profile, "utf8", "base64");
|
|
203
|
+
encrypted += cipher.final("base64");
|
|
204
|
+
// AEAD ciphers (e.g. aes-256-gcm) require the auth tag to be captured here and verified on decrypt via
|
|
205
|
+
// setAuthTag(), otherwise decoding throws "Unsupported state or unable to authenticate data" on every
|
|
206
|
+
// token. `final()` must be called before `getAuthTag()` - the tag isn't available until encryption
|
|
207
|
+
// has finished.
|
|
208
|
+
const authTag = JWTUtils.getAuthTagIfAEAD(cipher);
|
|
209
|
+
payload.profile = salt.toString("base64") + ":" + authTag + ":" + encrypted;
|
|
210
|
+
payload.encryption = true;
|
|
211
|
+
}
|
|
212
|
+
static async createToken(config, user, data) {
|
|
213
|
+
const { payload, passwordOptions } = JWTUtils.preparePayload(config, user, data);
|
|
214
|
+
if (passwordOptions) {
|
|
215
|
+
const salt = crypto.randomBytes(16);
|
|
216
|
+
const key = await JWTUtils.deriveKey(passwordOptions.password, salt, passwordOptions.algorithm);
|
|
217
|
+
JWTUtils.finishPasswordEncryption(payload, passwordOptions, key, salt);
|
|
143
218
|
}
|
|
144
219
|
JWTUtils.assertSafeAlgorithm(config);
|
|
145
220
|
return jwt.sign(payload, config.secret, config.options);
|
|
146
221
|
}
|
|
147
222
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* @param config The JWT configuration to use when validating the token.
|
|
152
|
-
* @param token The JWT token to validate.
|
|
153
|
-
* @returns The data encoded in the token's payload.
|
|
223
|
+
* Synchronous counterpart to `createToken()`. **Blocks the event loop** while deriving the encryption key
|
|
224
|
+
* when password-based payload encryption is configured (see `deriveKeySync`) - prefer `createToken()` on a
|
|
225
|
+
* request-handling path in that case.
|
|
154
226
|
*/
|
|
155
|
-
static
|
|
227
|
+
static createTokenSync(config, user, data) {
|
|
228
|
+
const { payload, passwordOptions } = JWTUtils.preparePayload(config, user, data);
|
|
229
|
+
if (passwordOptions) {
|
|
230
|
+
const salt = crypto.randomBytes(16);
|
|
231
|
+
const key = JWTUtils.deriveKeySync(passwordOptions.password, salt, passwordOptions.algorithm);
|
|
232
|
+
JWTUtils.finishPasswordEncryption(payload, passwordOptions, key, salt);
|
|
233
|
+
}
|
|
156
234
|
JWTUtils.assertSafeAlgorithm(config);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
235
|
+
return jwt.sign(payload, config.secret, config.options);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Verifies `token` and prepares its payload for `decodeToken`/`decodeTokenSync`: validates the signature/
|
|
239
|
+
* shape, and - for private-key decryption only, which has no async dependency - decrypts it in place.
|
|
240
|
+
* Password-based decryption is left for the caller to finish via `finishPasswordDecryption()`, since
|
|
241
|
+
* deriving the key is the one step that differs between the sync and async entry points.
|
|
242
|
+
*/
|
|
243
|
+
static preDecode(config, token) {
|
|
244
|
+
JWTUtils.assertSafeAlgorithm(config);
|
|
245
|
+
const payload = jwt.verify(token, config.secret, config.options);
|
|
160
246
|
if (!payload || !payload.profile) {
|
|
161
247
|
throw new Error("Token is invalid or missing data.");
|
|
162
248
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
//
|
|
249
|
+
let passwordOptions;
|
|
250
|
+
let salt;
|
|
251
|
+
let authTagB64;
|
|
252
|
+
let encryptedProfile;
|
|
253
|
+
// Decrypt the payload if desired. Must happen before decompression since compression is applied *before*
|
|
254
|
+
// encryption when the token is created, so decryption must be undone first.
|
|
169
255
|
if (payload.encryption && config.payload && config.payload.encrypt) {
|
|
170
256
|
const payloadOptions = config.payload;
|
|
171
257
|
if (payloadOptions.private_key) {
|
|
172
258
|
const keyOptions = payloadOptions;
|
|
173
|
-
|
|
174
|
-
payload.profile = decrypted.toString("utf8");
|
|
259
|
+
payload.profile = JWTUtils.hybridDecrypt(keyOptions.private_key, payload.profile);
|
|
175
260
|
}
|
|
176
261
|
else {
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
262
|
+
passwordOptions = payloadOptions;
|
|
263
|
+
const parts = payload.profile.split(":");
|
|
264
|
+
// The current format is `<salt>:<authTag>:<ciphertext>` (3 parts). A 2-part `<salt>:<ciphertext>`
|
|
265
|
+
// payload is the pre-AEAD-auth-tag format from before this method required an auth tag; without
|
|
266
|
+
// this check, `encryptedProfile` would silently come back `undefined` and decryption would be
|
|
267
|
+
// skipped, surfacing as an opaque JSON.parse SyntaxError in finalizePayload() instead of a clear
|
|
268
|
+
// error identifying the actual problem.
|
|
269
|
+
if (parts.length !== 3) {
|
|
270
|
+
throw new Error("Token payload uses an unrecognized or outdated encrypted format and cannot be decoded.");
|
|
271
|
+
}
|
|
272
|
+
const [saltB64, tagB64, profile] = parts;
|
|
273
|
+
salt = Buffer.from(saltB64, "base64");
|
|
274
|
+
authTagB64 = tagB64;
|
|
275
|
+
encryptedProfile = profile;
|
|
186
276
|
}
|
|
187
277
|
}
|
|
188
|
-
|
|
278
|
+
return { payload, passwordOptions, salt, authTagB64, encryptedProfile };
|
|
279
|
+
}
|
|
280
|
+
/** Finishes password-based payload decryption once `key` has been derived (sync or async). */
|
|
281
|
+
static finishPasswordDecryption(payload, passwordOptions, key, encryptedProfile, authTagB64) {
|
|
282
|
+
const iv = Buffer.from(passwordOptions.iv);
|
|
283
|
+
const decipher = crypto.createDecipheriv(passwordOptions.algorithm, key, iv);
|
|
284
|
+
if (authTagB64) {
|
|
285
|
+
decipher.setAuthTag(Buffer.from(authTagB64, "base64"));
|
|
286
|
+
}
|
|
287
|
+
let decrypted = decipher.update(encryptedProfile, "base64", "utf8");
|
|
288
|
+
decrypted += decipher.final("utf8");
|
|
289
|
+
payload.profile = decrypted;
|
|
290
|
+
}
|
|
291
|
+
/** Decompresses (if applicable) and parses the final payload profile shared by both decode entry points. */
|
|
292
|
+
static finalizePayload(payload) {
|
|
293
|
+
if (payload.compression === JWTUtilsCompressionMethods.ZLIB) {
|
|
294
|
+
const buf = Buffer.from(payload.profile, "base64");
|
|
295
|
+
// Cap decompressed size against a decompression bomb (a small compressed payload expanding to consume
|
|
296
|
+
// excessive memory). Requires a validly-signed token, but costs nothing to bound given every other
|
|
297
|
+
// cache/store in this codebase is similarly size-limited.
|
|
298
|
+
payload.profile = zlib
|
|
299
|
+
.gunzipSync(buf, { maxOutputLength: JWTUtils.MAX_DECOMPRESSED_PROFILE_BYTES })
|
|
300
|
+
.toString("utf-8");
|
|
301
|
+
}
|
|
189
302
|
payload.profile = JSON.parse(payload.profile);
|
|
190
303
|
return payload;
|
|
191
304
|
}
|
|
@@ -197,43 +310,35 @@ export class JWTUtils {
|
|
|
197
310
|
* @param token The JWT token to validate.
|
|
198
311
|
* @returns The data encoded in the token's payload.
|
|
199
312
|
*/
|
|
200
|
-
static
|
|
201
|
-
JWTUtils.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (!payload || !payload.profile) {
|
|
206
|
-
throw new Error("Token is invalid or missing data.");
|
|
207
|
-
}
|
|
208
|
-
// Decompress the payload if desired
|
|
209
|
-
if (payload.compression === JWTUtilsCompressionMethods.ZLIB) {
|
|
210
|
-
const buf = Buffer.from(payload.profile, "base64");
|
|
211
|
-
payload.profile = zlib.gunzipSync(buf).toString("utf-8");
|
|
313
|
+
static async decodeToken(config, token) {
|
|
314
|
+
const { payload, passwordOptions, salt, authTagB64, encryptedProfile } = JWTUtils.preDecode(config, token);
|
|
315
|
+
if (passwordOptions && salt && encryptedProfile !== undefined) {
|
|
316
|
+
const key = await JWTUtils.deriveKey(passwordOptions.password, salt, passwordOptions.algorithm);
|
|
317
|
+
JWTUtils.finishPasswordDecryption(payload, passwordOptions, key, encryptedProfile, authTagB64);
|
|
212
318
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
decrypted += decipher.final("utf8");
|
|
230
|
-
payload.profile = decrypted;
|
|
231
|
-
}
|
|
319
|
+
return JWTUtils.finalizePayload(payload);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Synchronous counterpart to `decodeToken()`. **Blocks the event loop** while deriving the decryption key
|
|
323
|
+
* when password-based payload encryption is configured (see `deriveKeySync`) - prefer `decodeToken()` on a
|
|
324
|
+
* request-handling path in that case.
|
|
325
|
+
*
|
|
326
|
+
* @param config The JWT configuration to use when validating the token.
|
|
327
|
+
* @param token The JWT token to validate.
|
|
328
|
+
* @returns The data encoded in the token's payload.
|
|
329
|
+
*/
|
|
330
|
+
static decodeTokenSync(config, token) {
|
|
331
|
+
const { payload, passwordOptions, salt, authTagB64, encryptedProfile } = JWTUtils.preDecode(config, token);
|
|
332
|
+
if (passwordOptions && salt && encryptedProfile !== undefined) {
|
|
333
|
+
const key = JWTUtils.deriveKeySync(passwordOptions.password, salt, passwordOptions.algorithm);
|
|
334
|
+
JWTUtils.finishPasswordDecryption(payload, passwordOptions, key, encryptedProfile, authTagB64);
|
|
232
335
|
}
|
|
233
|
-
|
|
234
|
-
payload.profile = JSON.parse(payload.profile);
|
|
235
|
-
return payload;
|
|
336
|
+
return JWTUtils.finalizePayload(payload);
|
|
236
337
|
}
|
|
237
338
|
}
|
|
238
|
-
|
|
339
|
+
/** HMAC algorithm names that must never be permitted alongside a non-HMAC secret (see `assertSafeAlgorithm`). */
|
|
340
|
+
JWTUtils.HMAC_ALGORITHMS = new Set(["HS256", "HS384", "HS512"]);
|
|
341
|
+
/** Maximum size, in bytes, a compressed profile is allowed to decompress to (see `finalizePayload`). Guards
|
|
342
|
+
* against a decompression bomb - a small compressed payload expanding to consume excessive memory. */
|
|
343
|
+
JWTUtils.MAX_DECOMPRESSED_PROFILE_BYTES = 10 * 1024 * 1024;
|
|
239
344
|
//# sourceMappingURL=JWTUtils.js.map
|
package/dist/lib/JWTUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JWTUtils.js","sourceRoot":"","sources":["../../src/JWTUtils.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JWTUtils.js","sourceRoot":"","sources":["../../src/JWTUtils.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/Logger.js
CHANGED
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
///////////////////////////////////////////////////////////////////////////////
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import winston from "winston";
|
|
6
|
+
import { CacheUtils } from "./CacheUtils.js";
|
|
6
7
|
const { format, transports } = winston;
|
|
7
8
|
const { combine, timestamp, printf } = format;
|
|
8
9
|
export const FILENAME = fileURLToPath(import.meta.url).replace(/\\/g, "/");
|
|
9
|
-
// The default stack trace limit (10) is too shallow once a few frames of winston/logform internals are on the
|
|
10
|
-
// stack, causing the real caller frame that `source()` below looks for to be truncated. Widen it so the caller is
|
|
11
|
-
// always captured.
|
|
12
|
-
Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 30);
|
|
13
10
|
export const logFormat = printf((info) => {
|
|
14
11
|
const prefix = info.source ? `[${info.source}] ` : "";
|
|
15
12
|
return `${prefix}${info.timestamp} ${info.level}: ${info.message}`;
|
|
@@ -24,7 +21,14 @@ export const logFormat = printf((info) => {
|
|
|
24
21
|
* call stack in either case.
|
|
25
22
|
*/
|
|
26
23
|
export const source = format((info) => {
|
|
24
|
+
// The default stack trace limit (10) is too shallow once a few frames of winston/logform internals are on
|
|
25
|
+
// the stack, causing the real caller frame below to be truncated. The limit is widened only for the duration
|
|
26
|
+
// of this capture (rather than mutated globally for the whole process) so every other `Error` thrown
|
|
27
|
+
// anywhere in the application doesn't pay the cost of a permanently-widened trace.
|
|
28
|
+
const originalStackTraceLimit = Error.stackTraceLimit;
|
|
29
|
+
Error.stackTraceLimit = Math.max(originalStackTraceLimit, 30);
|
|
27
30
|
const stack = new Error().stack?.split("\n") ?? [];
|
|
31
|
+
Error.stackTraceLimit = originalStackTraceLimit;
|
|
28
32
|
for (const line of stack) {
|
|
29
33
|
if (line.includes(FILENAME) || line.includes("node_modules") || line.includes("node:internal")) {
|
|
30
34
|
continue;
|
|
@@ -44,6 +48,11 @@ export const source = format((info) => {
|
|
|
44
48
|
}
|
|
45
49
|
return info;
|
|
46
50
|
});
|
|
51
|
+
/** Maximum number of distinct `${level}:${file}` logger instances to keep cached. Each `file`-bound entry holds
|
|
52
|
+
* open file descriptors via winston's `File` transport, so an unbounded cache would leak descriptors indefinitely
|
|
53
|
+
* for any caller that varies `file` per call (e.g. a per-request or per-session name) instead of reusing a fixed
|
|
54
|
+
* small set of names. */
|
|
55
|
+
const MAX_CACHED_LOGGERS = 100;
|
|
47
56
|
const _loggerCache = new Map();
|
|
48
57
|
/**
|
|
49
58
|
* Creates (or retrieves a cached) logger with the specified level and file name to output logs to.
|
|
@@ -54,18 +63,41 @@ const _loggerCache = new Map();
|
|
|
54
63
|
export const Logger = function (level = "debug", file = undefined) {
|
|
55
64
|
const cacheKey = `${level}:${file ?? ""}`;
|
|
56
65
|
if (_loggerCache.has(cacheKey)) {
|
|
57
|
-
|
|
66
|
+
const cached = _loggerCache.get(cacheKey);
|
|
67
|
+
// Move to the end of the Map's iteration order so a frequently-reused logger isn't evicted (and its
|
|
68
|
+
// file transport closed, possibly mid-write) ahead of one that's actually gone idle - Map.set() on an
|
|
69
|
+
// already-present key doesn't reorder it by itself.
|
|
70
|
+
_loggerCache.delete(cacheKey);
|
|
71
|
+
_loggerCache.set(cacheKey, cached);
|
|
72
|
+
return cached;
|
|
58
73
|
}
|
|
59
|
-
|
|
74
|
+
// `colorize()` wraps `info.level` in ANSI escape codes unconditionally - it doesn't detect whether the
|
|
75
|
+
// destination is a TTY. It must stay Console-only rather than living in the logger-level `format` below:
|
|
76
|
+
// winston applies the logger-level format to every transport that doesn't supply its own override -
|
|
77
|
+
// including the File transports, and any transport a caller adds later via `logger.add()` - so baking
|
|
78
|
+
// colorize() into it would corrupt on-disk logs and any other attached transport with escape sequences that
|
|
79
|
+
// break grep/log shippers/aggregators expecting a plain-text level field. The logger-level format is left as
|
|
80
|
+
// the uncolored base precisely so those other transports still inherit sensible plain-text formatting.
|
|
81
|
+
const base = combine(format.splat(), format.simple(), timestamp(), source(), logFormat);
|
|
82
|
+
const transport = [new transports.Console({ format: combine(format.colorize(), base) })];
|
|
60
83
|
if (file) {
|
|
61
84
|
transport.push(new winston.transports.File({ filename: file + "error.log", level: "error" }));
|
|
62
85
|
transport.push(new winston.transports.File({ filename: file + ".log" }));
|
|
63
86
|
}
|
|
64
87
|
const logger = winston.createLogger({
|
|
65
88
|
level,
|
|
66
|
-
format:
|
|
89
|
+
format: base,
|
|
67
90
|
transports: transport,
|
|
68
91
|
});
|
|
92
|
+
if (_loggerCache.size >= MAX_CACHED_LOGGERS) {
|
|
93
|
+
// Non-null: the size check above guarantees the cache is non-empty, so `.next()` always yields a real key.
|
|
94
|
+
const oldestKey = _loggerCache.keys().next().value;
|
|
95
|
+
const oldest = _loggerCache.get(oldestKey);
|
|
96
|
+
CacheUtils.evictOldest(_loggerCache);
|
|
97
|
+
// Close the evicted logger's transports so its file descriptors are actually released, not just
|
|
98
|
+
// dropped from the cache while still held open by winston.
|
|
99
|
+
oldest?.close?.();
|
|
100
|
+
}
|
|
69
101
|
_loggerCache.set(cacheKey, logger);
|
|
70
102
|
return logger;
|
|
71
103
|
};
|