joye-backend-utility 7.4.1 → 8.0.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/dist/jwt.js
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
const folderPath = path.resolve(`${__dirname}`);
|
|
8
8
|
const JWT_PRIVATE_KEY = fs.readFileSync(`${folderPath}/jwtKeys/jwtRS256.key`, 'utf8');
|
|
9
9
|
const JWT_PUBLIC_KEY = fs.readFileSync(`${folderPath}/jwtKeys/jwtRS256.key.pub`, 'utf8');
|
|
10
|
+
const ALLOWED_JWT_ALGORITHMS = ['RS256'];
|
|
10
11
|
const createToken = async (payload, expiresIn) => {
|
|
11
12
|
const token = jwt.sign(payload, { key: JWT_PRIVATE_KEY.replace(/\\n/gm, '\n'), passphrase: process.env.JWT_SECRET }, {
|
|
12
13
|
expiresIn,
|
|
@@ -16,7 +17,12 @@ const createToken = async (payload, expiresIn) => {
|
|
|
16
17
|
};
|
|
17
18
|
exports.createToken = createToken;
|
|
18
19
|
const jwtVerify = async (token) => new Promise(resolve => {
|
|
19
|
-
|
|
20
|
+
var _a;
|
|
21
|
+
const decodedHeader = jwt.decode(token, { complete: true });
|
|
22
|
+
if (!((_a = decodedHeader === null || decodedHeader === void 0 ? void 0 : decodedHeader.header) === null || _a === void 0 ? void 0 : _a.alg) || decodedHeader.header.alg === 'none') {
|
|
23
|
+
return resolve(new Error('Invalid token algorithm'));
|
|
24
|
+
}
|
|
25
|
+
jwt.verify(token, JWT_PUBLIC_KEY.replace(/\\n/gm, '\n'), { algorithms: ALLOWED_JWT_ALGORITHMS, ignoreExpiration: false }, async (err, decoded) => {
|
|
20
26
|
if (err) {
|
|
21
27
|
return resolve(err);
|
|
22
28
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const assert = require("assert");
|
|
4
|
+
const jwt = require('jsonwebtoken');
|
|
5
|
+
const jwt_1 = require("../jwt");
|
|
6
|
+
const run = async () => {
|
|
7
|
+
const payload = {
|
|
8
|
+
userId: 'security-test-user',
|
|
9
|
+
email: 'security-test@example.com',
|
|
10
|
+
};
|
|
11
|
+
const noneToken = jwt.sign(payload, null, { algorithm: 'none' });
|
|
12
|
+
const noneResult = await (0, jwt_1.jwtVerify)(noneToken);
|
|
13
|
+
assert.ok(noneResult instanceof Error, 'Expected alg=none token to be rejected');
|
|
14
|
+
const hsToken = jwt.sign(payload, 'not-rs256-key', { algorithm: 'HS256' });
|
|
15
|
+
const hsResult = await (0, jwt_1.jwtVerify)(hsToken);
|
|
16
|
+
assert.ok(hsResult instanceof Error, 'Expected HS256 token to be rejected');
|
|
17
|
+
// Expiration-focused checks (mock verify/decode to isolate jwtVerify behavior)
|
|
18
|
+
const originalVerify = jwt.verify;
|
|
19
|
+
const originalDecode = jwt.decode;
|
|
20
|
+
try {
|
|
21
|
+
jwt.decode = () => ({ header: { alg: 'RS256' } });
|
|
22
|
+
// Valid token path
|
|
23
|
+
let capturedOptions = null;
|
|
24
|
+
jwt.verify = (_token, _key, options, callback) => {
|
|
25
|
+
capturedOptions = options;
|
|
26
|
+
callback(null, { userId: payload.userId });
|
|
27
|
+
};
|
|
28
|
+
const validResult = await (0, jwt_1.jwtVerify)('valid-rs256-token');
|
|
29
|
+
assert.ok(!(validResult instanceof Error), 'Expected valid token to be accepted');
|
|
30
|
+
assert.deepStrictEqual(capturedOptions.algorithms, ['RS256'], 'Expected RS256 algorithm allowlist');
|
|
31
|
+
assert.strictEqual(capturedOptions.ignoreExpiration, false, 'Expected ignoreExpiration to be false');
|
|
32
|
+
// Near-expiry token path (still valid)
|
|
33
|
+
jwt.verify = (_token, _key, _options, callback) => {
|
|
34
|
+
callback(null, { userId: payload.userId, exp: Math.floor(Date.now() / 1000) + 2 });
|
|
35
|
+
};
|
|
36
|
+
const nearExpiryResult = await (0, jwt_1.jwtVerify)('near-expiry-rs256-token');
|
|
37
|
+
assert.ok(!(nearExpiryResult instanceof Error), 'Expected near-expiry token to be accepted');
|
|
38
|
+
// Expired token path
|
|
39
|
+
jwt.verify = (_token, _key, _options, callback) => {
|
|
40
|
+
const expiredError = new Error('jwt expired');
|
|
41
|
+
expiredError.name = 'TokenExpiredError';
|
|
42
|
+
callback(expiredError, null);
|
|
43
|
+
};
|
|
44
|
+
const expiredResult = await (0, jwt_1.jwtVerify)('expired-rs256-token');
|
|
45
|
+
assert.ok(expiredResult instanceof Error, 'Expected expired token to be rejected');
|
|
46
|
+
assert.strictEqual(expiredResult.name, 'TokenExpiredError', 'Expected TokenExpiredError for expired token');
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
jwt.verify = originalVerify;
|
|
50
|
+
jwt.decode = originalDecode;
|
|
51
|
+
}
|
|
52
|
+
console.log('JWT algorithm validation tests passed.');
|
|
53
|
+
};
|
|
54
|
+
run().catch(error => {
|
|
55
|
+
console.error('JWT algorithm validation tests failed:', error);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joye-backend-utility",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "Joye backend utility for db functions and common functions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc && yarn copy-files",
|
|
15
15
|
"test": "echo \"Error: no test specified\"",
|
|
16
|
+
"test:jwt-algorithm": "ts-node lib/tests/jwtAlgorithmValidation.test.ts",
|
|
16
17
|
"postinstall": "npm run build",
|
|
17
18
|
"lint": "eslint --ignore-path .gitignore --ext .ts .",
|
|
18
19
|
"lint:fix": "npm run lint -- --fix",
|