@naman_deep_singh/security 1.3.0 → 1.3.2
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/README.md +1 -1
- package/dist/cjs/core/crypto/cryptoManager.js +9 -3
- package/dist/cjs/core/crypto/decrypt.js +6 -6
- package/dist/cjs/core/crypto/encrypt.js +4 -4
- package/dist/cjs/core/crypto/hmac.js +1 -1
- package/dist/cjs/core/crypto/index.d.ts +5 -5
- package/dist/cjs/core/crypto/random.js +2 -2
- package/dist/cjs/core/jwt/decode.d.ts +1 -1
- package/dist/cjs/core/jwt/decode.js +2 -2
- package/dist/cjs/core/jwt/extractToken.js +7 -7
- package/dist/cjs/core/jwt/generateTokens.d.ts +2 -2
- package/dist/cjs/core/jwt/generateTokens.js +10 -6
- package/dist/cjs/core/jwt/index.d.ts +8 -8
- package/dist/cjs/core/jwt/jwtManager.d.ts +3 -2
- package/dist/cjs/core/jwt/jwtManager.js +66 -86
- package/dist/cjs/core/jwt/parseDuration.js +3 -3
- package/dist/cjs/core/jwt/signToken.d.ts +1 -1
- package/dist/cjs/core/jwt/signToken.js +7 -7
- package/dist/cjs/core/jwt/types.d.ts +1 -1
- package/dist/cjs/core/jwt/validateToken.d.ts +2 -2
- package/dist/cjs/core/jwt/validateToken.js +3 -3
- package/dist/cjs/core/jwt/verify.d.ts +3 -2
- package/dist/cjs/core/password/hash.js +1 -1
- package/dist/cjs/core/password/index.d.ts +3 -3
- package/dist/cjs/core/password/passwordManager.d.ts +1 -1
- package/dist/cjs/core/password/passwordManager.js +32 -31
- package/dist/cjs/core/password/strength.d.ts +1 -1
- package/dist/cjs/core/password/strength.js +4 -4
- package/dist/cjs/core/password/utils.js +2 -2
- package/dist/cjs/core/password/verify.js +1 -1
- package/dist/cjs/index.d.ts +6 -6
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/interfaces/jwt.interface.d.ts +1 -1
- package/dist/esm/core/crypto/cryptoManager.js +10 -4
- package/dist/esm/core/crypto/decrypt.js +7 -7
- package/dist/esm/core/crypto/encrypt.js +5 -5
- package/dist/esm/core/crypto/hmac.js +2 -2
- package/dist/esm/core/crypto/index.d.ts +5 -5
- package/dist/esm/core/crypto/index.js +5 -5
- package/dist/esm/core/crypto/random.js +3 -3
- package/dist/esm/core/jwt/decode.d.ts +1 -1
- package/dist/esm/core/jwt/decode.js +3 -3
- package/dist/esm/core/jwt/extractToken.js +7 -7
- package/dist/esm/core/jwt/generateTokens.d.ts +2 -2
- package/dist/esm/core/jwt/generateTokens.js +12 -8
- package/dist/esm/core/jwt/index.d.ts +8 -8
- package/dist/esm/core/jwt/index.js +8 -8
- package/dist/esm/core/jwt/jwtManager.d.ts +3 -2
- package/dist/esm/core/jwt/jwtManager.js +70 -90
- package/dist/esm/core/jwt/parseDuration.js +3 -3
- package/dist/esm/core/jwt/signToken.d.ts +1 -1
- package/dist/esm/core/jwt/signToken.js +9 -9
- package/dist/esm/core/jwt/types.d.ts +1 -1
- package/dist/esm/core/jwt/validateToken.d.ts +2 -2
- package/dist/esm/core/jwt/validateToken.js +3 -3
- package/dist/esm/core/jwt/verify.d.ts +3 -2
- package/dist/esm/core/jwt/verify.js +1 -1
- package/dist/esm/core/password/hash.js +3 -3
- package/dist/esm/core/password/index.d.ts +3 -3
- package/dist/esm/core/password/index.js +3 -3
- package/dist/esm/core/password/passwordManager.d.ts +1 -1
- package/dist/esm/core/password/passwordManager.js +34 -33
- package/dist/esm/core/password/strength.d.ts +1 -1
- package/dist/esm/core/password/strength.js +5 -5
- package/dist/esm/core/password/utils.js +4 -4
- package/dist/esm/core/password/verify.js +2 -2
- package/dist/esm/index.d.ts +6 -6
- package/dist/esm/index.js +7 -7
- package/dist/esm/interfaces/jwt.interface.d.ts +1 -1
- package/dist/types/core/crypto/index.d.ts +5 -5
- package/dist/types/core/jwt/decode.d.ts +1 -1
- package/dist/types/core/jwt/generateTokens.d.ts +2 -2
- package/dist/types/core/jwt/index.d.ts +8 -8
- package/dist/types/core/jwt/jwtManager.d.ts +3 -2
- package/dist/types/core/jwt/signToken.d.ts +1 -1
- package/dist/types/core/jwt/types.d.ts +1 -1
- package/dist/types/core/jwt/validateToken.d.ts +2 -2
- package/dist/types/core/jwt/verify.d.ts +3 -2
- package/dist/types/core/password/index.d.ts +3 -3
- package/dist/types/core/password/passwordManager.d.ts +1 -1
- package/dist/types/core/password/strength.d.ts +1 -1
- package/dist/types/index.d.ts +6 -6
- package/dist/types/interfaces/jwt.interface.d.ts +1 -1
- package/package.json +5 -4
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validateTokenPayload = validateTokenPayload;
|
|
4
4
|
exports.isTokenExpired = isTokenExpired;
|
|
5
5
|
function validateTokenPayload(payload, rules = {
|
|
6
|
-
requiredFields: [
|
|
6
|
+
requiredFields: ['exp', 'iat'],
|
|
7
7
|
}) {
|
|
8
|
-
const { requiredFields = [], forbiddenFields = [], validateTypes = {} } = rules;
|
|
8
|
+
const { requiredFields = [], forbiddenFields = [], validateTypes = {}, } = rules;
|
|
9
9
|
// 1. Required fields
|
|
10
10
|
for (const field of requiredFields) {
|
|
11
11
|
if (!(field in payload)) {
|
|
@@ -24,7 +24,7 @@ function validateTokenPayload(payload, rules = {
|
|
|
24
24
|
if (key in payload && typeof payload[key] !== expectedType) {
|
|
25
25
|
return {
|
|
26
26
|
valid: false,
|
|
27
|
-
error: `Invalid type for ${key}. Expected ${expectedType}
|
|
27
|
+
error: `Invalid type for ${key}. Expected ${expectedType}.`,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import jwt
|
|
2
|
-
import {
|
|
1
|
+
import type jwt from 'jsonwebtoken';
|
|
2
|
+
import { type JwtPayload, type Secret } from 'jsonwebtoken';
|
|
3
|
+
import type { VerificationResult } from './types';
|
|
3
4
|
/**
|
|
4
5
|
* Verify token (throws if invalid or expired)
|
|
5
6
|
*/
|
|
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.hashPasswordSync = exports.hashPassword = void 0;
|
|
7
7
|
exports.hashPasswordWithPepper = hashPasswordWithPepper;
|
|
8
8
|
exports.hashPasswordWithPepperSync = hashPasswordWithPepperSync;
|
|
9
|
+
const errors_utils_1 = require("@naman_deep_singh/errors-utils");
|
|
9
10
|
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
10
11
|
const utils_1 = require("./utils");
|
|
11
|
-
const errors_utils_1 = require("@naman_deep_singh/errors-utils");
|
|
12
12
|
/**
|
|
13
13
|
* Hash a password asynchronously using bcrypt.
|
|
14
14
|
*/
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from './hash';
|
|
2
|
+
export * from './strength';
|
|
3
|
+
export * from './verify';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IPasswordManager, PasswordConfig,
|
|
1
|
+
import type { HashedPassword, IPasswordManager, PasswordConfig, PasswordStrength, PasswordValidationResult } from '../../interfaces/password.interface';
|
|
2
2
|
export declare class PasswordManager implements IPasswordManager {
|
|
3
3
|
private defaultConfig;
|
|
4
4
|
constructor(config?: PasswordConfig);
|
|
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PasswordManager = void 0;
|
|
7
|
-
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
8
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
-
const
|
|
8
|
+
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
10
9
|
const errors_utils_1 = require("@naman_deep_singh/errors-utils");
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
11
|
class PasswordManager {
|
|
12
12
|
constructor(config = {}) {
|
|
13
13
|
this.defaultConfig = {
|
|
@@ -18,7 +18,7 @@ class PasswordManager {
|
|
|
18
18
|
requireLowercase: true,
|
|
19
19
|
requireNumbers: true,
|
|
20
20
|
requireSpecialChars: false,
|
|
21
|
-
...config
|
|
21
|
+
...config,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
@@ -37,14 +37,15 @@ class PasswordManager {
|
|
|
37
37
|
const hash = await bcryptjs_1.default.hash(password, passwordSalt);
|
|
38
38
|
return {
|
|
39
39
|
hash,
|
|
40
|
-
salt: passwordSalt
|
|
40
|
+
salt: passwordSalt,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
44
|
-
if (error instanceof errors_utils_1.BadRequestError ||
|
|
44
|
+
if (error instanceof errors_utils_1.BadRequestError ||
|
|
45
|
+
error instanceof errors_utils_1.ValidationError) {
|
|
45
46
|
throw error;
|
|
46
47
|
}
|
|
47
|
-
throw new errors_utils_1.BadRequestError(
|
|
48
|
+
throw new errors_utils_1.BadRequestError('Failed to hash password');
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
@@ -76,14 +77,14 @@ class PasswordManager {
|
|
|
76
77
|
if (length < config.minLength || length > config.maxLength) {
|
|
77
78
|
throw new errors_utils_1.ValidationError(`Password length must be between ${config.minLength} and ${config.maxLength}`);
|
|
78
79
|
}
|
|
79
|
-
let charset =
|
|
80
|
+
let charset = 'abcdefghijklmnopqrstuvwxyz';
|
|
80
81
|
if (config.requireUppercase)
|
|
81
|
-
charset +=
|
|
82
|
+
charset += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
82
83
|
if (config.requireNumbers)
|
|
83
|
-
charset +=
|
|
84
|
+
charset += '0123456789';
|
|
84
85
|
if (config.requireSpecialChars)
|
|
85
|
-
charset +=
|
|
86
|
-
let password =
|
|
86
|
+
charset += '!@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
87
|
+
let password = '';
|
|
87
88
|
const randomBytes = crypto_1.default.randomBytes(length);
|
|
88
89
|
for (let i = 0; i < length; i++) {
|
|
89
90
|
password += charset[randomBytes[i] % charset.length];
|
|
@@ -110,8 +111,8 @@ class PasswordManager {
|
|
|
110
111
|
const finalConfig = { ...this.defaultConfig, ...config };
|
|
111
112
|
const errors = [];
|
|
112
113
|
// Basic validation
|
|
113
|
-
if (!password || typeof password !==
|
|
114
|
-
errors.push(
|
|
114
|
+
if (!password || typeof password !== 'string') {
|
|
115
|
+
errors.push('Password must be a non-empty string');
|
|
115
116
|
}
|
|
116
117
|
// Length validation
|
|
117
118
|
if (password.length < finalConfig.minLength) {
|
|
@@ -122,20 +123,20 @@ class PasswordManager {
|
|
|
122
123
|
}
|
|
123
124
|
// Complexity requirements
|
|
124
125
|
if (finalConfig.requireUppercase && !/[A-Z]/.test(password)) {
|
|
125
|
-
errors.push(
|
|
126
|
+
errors.push('Password must contain at least one uppercase letter');
|
|
126
127
|
}
|
|
127
128
|
if (finalConfig.requireLowercase && !/[a-z]/.test(password)) {
|
|
128
|
-
errors.push(
|
|
129
|
+
errors.push('Password must contain at least one lowercase letter');
|
|
129
130
|
}
|
|
130
131
|
if (finalConfig.requireNumbers && !/[0-9]/.test(password)) {
|
|
131
|
-
errors.push(
|
|
132
|
+
errors.push('Password must contain at least one number');
|
|
132
133
|
}
|
|
133
134
|
if (finalConfig.requireSpecialChars && !/[^A-Za-z0-9]/.test(password)) {
|
|
134
|
-
errors.push(
|
|
135
|
+
errors.push('Password must contain at least one special character');
|
|
135
136
|
}
|
|
136
137
|
// Custom rules
|
|
137
138
|
if (finalConfig.customRules) {
|
|
138
|
-
finalConfig.customRules.forEach(rule => {
|
|
139
|
+
finalConfig.customRules.forEach((rule) => {
|
|
139
140
|
if (!rule.test(password)) {
|
|
140
141
|
errors.push(rule.message);
|
|
141
142
|
}
|
|
@@ -146,7 +147,7 @@ class PasswordManager {
|
|
|
146
147
|
return {
|
|
147
148
|
isValid,
|
|
148
149
|
errors,
|
|
149
|
-
strength
|
|
150
|
+
strength,
|
|
150
151
|
};
|
|
151
152
|
}
|
|
152
153
|
/**
|
|
@@ -176,25 +177,25 @@ class PasswordManager {
|
|
|
176
177
|
// Common patterns deduction
|
|
177
178
|
if (/^[A-Za-z]+$/.test(password)) {
|
|
178
179
|
score--;
|
|
179
|
-
feedback.push(
|
|
180
|
+
feedback.push('Consider adding numbers and symbols');
|
|
180
181
|
}
|
|
181
182
|
if (/^[0-9]+$/.test(password)) {
|
|
182
183
|
score -= 2;
|
|
183
|
-
feedback.push(
|
|
184
|
+
feedback.push('Avoid using only numbers');
|
|
184
185
|
}
|
|
185
186
|
if (/([a-zA-Z0-9])\1{2,}/.test(password)) {
|
|
186
187
|
score--;
|
|
187
|
-
feedback.push(
|
|
188
|
+
feedback.push('Avoid repeated characters');
|
|
188
189
|
}
|
|
189
190
|
if (/(?:012|123|234|345|456|567|678|789)/.test(password)) {
|
|
190
191
|
score--;
|
|
191
|
-
feedback.push(
|
|
192
|
+
feedback.push('Avoid sequential patterns');
|
|
192
193
|
}
|
|
193
194
|
// Common passwords check
|
|
194
195
|
const commonPasswords = ['password', '123456', 'qwerty', 'admin', 'letmein'];
|
|
195
|
-
if (commonPasswords.some(common => password.toLowerCase().includes(common))) {
|
|
196
|
+
if (commonPasswords.some((common) => password.toLowerCase().includes(common))) {
|
|
196
197
|
score = 0;
|
|
197
|
-
feedback.push(
|
|
198
|
+
feedback.push('Avoid common passwords');
|
|
198
199
|
}
|
|
199
200
|
// Clamp score and determine label
|
|
200
201
|
score = Math.max(0, Math.min(4, score));
|
|
@@ -202,23 +203,23 @@ class PasswordManager {
|
|
|
202
203
|
switch (score) {
|
|
203
204
|
case 0:
|
|
204
205
|
label = 'very-weak';
|
|
205
|
-
suggestions.push(
|
|
206
|
+
suggestions.push('Use a longer password with mixed characters');
|
|
206
207
|
break;
|
|
207
208
|
case 1:
|
|
208
209
|
label = 'weak';
|
|
209
|
-
suggestions.push(
|
|
210
|
+
suggestions.push('Add more character variety');
|
|
210
211
|
break;
|
|
211
212
|
case 2:
|
|
212
213
|
label = 'fair';
|
|
213
|
-
suggestions.push(
|
|
214
|
+
suggestions.push('Consider adding more length or character types');
|
|
214
215
|
break;
|
|
215
216
|
case 3:
|
|
216
217
|
label = 'good';
|
|
217
|
-
suggestions.push(
|
|
218
|
+
suggestions.push('Your password is reasonably secure');
|
|
218
219
|
break;
|
|
219
220
|
case 4:
|
|
220
221
|
label = 'strong';
|
|
221
|
-
suggestions.push(
|
|
222
|
+
suggestions.push('Your password is very secure');
|
|
222
223
|
break;
|
|
223
224
|
default:
|
|
224
225
|
label = 'very-weak';
|
|
@@ -227,7 +228,7 @@ class PasswordManager {
|
|
|
227
228
|
score,
|
|
228
229
|
label,
|
|
229
230
|
feedback,
|
|
230
|
-
suggestions
|
|
231
|
+
suggestions,
|
|
231
232
|
};
|
|
232
233
|
}
|
|
233
234
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { PasswordStrengthOptions } from
|
|
1
|
+
import type { PasswordStrengthOptions } from './types';
|
|
2
2
|
export declare const isPasswordStrong: (password: string, options?: PasswordStrengthOptions) => boolean;
|
|
@@ -9,13 +9,13 @@ const isPasswordStrong = (password, options = {}) => {
|
|
|
9
9
|
if (password.length < minLength)
|
|
10
10
|
throw new errors_utils_1.ValidationError(`Password must be at least ${minLength} characters`);
|
|
11
11
|
if (requireUppercase && !/[A-Z]/.test(password))
|
|
12
|
-
throw new errors_utils_1.ValidationError(
|
|
12
|
+
throw new errors_utils_1.ValidationError('Password must include uppercase letters');
|
|
13
13
|
if (requireLowercase && !/[a-z]/.test(password))
|
|
14
|
-
throw new errors_utils_1.ValidationError(
|
|
14
|
+
throw new errors_utils_1.ValidationError('Password must include lowercase letters');
|
|
15
15
|
if (requireNumbers && !/[0-9]/.test(password))
|
|
16
|
-
throw new errors_utils_1.ValidationError(
|
|
16
|
+
throw new errors_utils_1.ValidationError('Password must include numbers');
|
|
17
17
|
if (requireSymbols && !/[^A-Za-z0-9]/.test(password))
|
|
18
|
-
throw new errors_utils_1.ValidationError(
|
|
18
|
+
throw new errors_utils_1.ValidationError('Password must include symbols');
|
|
19
19
|
return true;
|
|
20
20
|
};
|
|
21
21
|
exports.isPasswordStrong = isPasswordStrong;
|
|
@@ -10,7 +10,7 @@ exports.normalizePassword = normalizePassword;
|
|
|
10
10
|
const crypto_1 = __importDefault(require("crypto"));
|
|
11
11
|
const errors_utils_1 = require("@naman_deep_singh/errors-utils");
|
|
12
12
|
function ensureValidPassword(password) {
|
|
13
|
-
if (!password || typeof password !==
|
|
13
|
+
if (!password || typeof password !== 'string') {
|
|
14
14
|
throw new errors_utils_1.BadRequestError('Invalid password provided');
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -34,5 +34,5 @@ function estimatePasswordEntropy(password) {
|
|
|
34
34
|
return password.length * Math.log2(pool);
|
|
35
35
|
}
|
|
36
36
|
function normalizePassword(password) {
|
|
37
|
-
return password.normalize(
|
|
37
|
+
return password.normalize('NFKC');
|
|
38
38
|
}
|
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.verifyPasswordSync = exports.verifyPassword = void 0;
|
|
7
7
|
exports.verifyPasswordWithPepper = verifyPasswordWithPepper;
|
|
8
8
|
exports.verifyPasswordWithPepperSync = verifyPasswordWithPepperSync;
|
|
9
|
-
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
10
9
|
const errors_utils_1 = require("@naman_deep_singh/errors-utils");
|
|
10
|
+
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
11
11
|
/**
|
|
12
12
|
* Compare a password with a stored hash asynchronously.
|
|
13
13
|
*/
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError } from
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
1
|
+
export * from './core/password';
|
|
2
|
+
export * from './core/jwt';
|
|
3
|
+
export * from './core/crypto';
|
|
4
|
+
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors-utils';
|
|
5
|
+
import * as CryptoUtils from './core/crypto';
|
|
6
|
+
import * as JWTUtils from './core/jwt';
|
|
7
7
|
declare const _default: {
|
|
8
8
|
decrypt: (data: string, secret: string) => string;
|
|
9
9
|
encrypt: (text: string, secret: string) => string;
|
package/dist/cjs/index.js
CHANGED
|
@@ -46,9 +46,9 @@ Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: funct
|
|
|
46
46
|
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return errors_utils_1.UnauthorizedError; } });
|
|
47
47
|
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_utils_1.ValidationError; } });
|
|
48
48
|
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return errors_utils_1.InternalServerError; } });
|
|
49
|
-
const PasswordUtils = __importStar(require("./core/password"));
|
|
50
|
-
const JWTUtils = __importStar(require("./core/jwt"));
|
|
51
49
|
const CryptoUtils = __importStar(require("./core/crypto"));
|
|
50
|
+
const JWTUtils = __importStar(require("./core/jwt"));
|
|
51
|
+
const PasswordUtils = __importStar(require("./core/password"));
|
|
52
52
|
exports.default = {
|
|
53
53
|
...PasswordUtils,
|
|
54
54
|
...JWTUtils,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { decrypt as functionalDecrypt, encrypt as functionalEncrypt, hmacSign as functionalHmacSign, hmacVerify as functionalHmacVerify, randomToken as functionalRandomToken, } from './index';
|
|
2
2
|
/**
|
|
3
3
|
* Default configuration
|
|
4
4
|
*/
|
|
5
5
|
const DEFAULT_CONFIG = {
|
|
6
6
|
defaultAlgorithm: 'aes-256-gcm',
|
|
7
7
|
defaultEncoding: 'utf8',
|
|
8
|
-
hmacAlgorithm: 'sha256'
|
|
8
|
+
hmacAlgorithm: 'sha256',
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
11
|
* CryptoManager - Class-based wrapper for all cryptographic operations
|
|
@@ -103,8 +103,14 @@ export class CryptoManager {
|
|
|
103
103
|
const crypto = require('crypto');
|
|
104
104
|
const keyPair = crypto.generateKeyPairSync('rsa', {
|
|
105
105
|
modulusLength: options?.modulusLength || 2048,
|
|
106
|
-
publicKeyEncoding: options?.publicKeyEncoding || {
|
|
107
|
-
|
|
106
|
+
publicKeyEncoding: options?.publicKeyEncoding || {
|
|
107
|
+
type: 'spki',
|
|
108
|
+
format: 'pem',
|
|
109
|
+
},
|
|
110
|
+
privateKeyEncoding: options?.privateKeyEncoding || {
|
|
111
|
+
type: 'pkcs8',
|
|
112
|
+
format: 'pem',
|
|
113
|
+
},
|
|
108
114
|
});
|
|
109
115
|
resolve(keyPair);
|
|
110
116
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import crypto from
|
|
2
|
-
const ALGO =
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
const ALGO = 'AES-256-GCM';
|
|
3
3
|
export const decrypt = (data, secret) => {
|
|
4
|
-
const [ivHex, encryptedHex] = data.split(
|
|
5
|
-
const iv = Buffer.from(ivHex,
|
|
6
|
-
const encrypted = Buffer.from(encryptedHex,
|
|
7
|
-
const key = crypto.createHash(
|
|
4
|
+
const [ivHex, encryptedHex] = data.split(':');
|
|
5
|
+
const iv = Buffer.from(ivHex, 'hex');
|
|
6
|
+
const encrypted = Buffer.from(encryptedHex, 'hex');
|
|
7
|
+
const key = crypto.createHash('sha256').update(secret).digest();
|
|
8
8
|
const decipher = crypto.createDecipheriv(ALGO, key, iv);
|
|
9
9
|
const decrypted = Buffer.concat([
|
|
10
10
|
decipher.update(encrypted),
|
|
11
11
|
decipher.final(),
|
|
12
12
|
]);
|
|
13
|
-
return decrypted.toString(
|
|
13
|
+
return decrypted.toString('utf8');
|
|
14
14
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import crypto from
|
|
2
|
-
const ALGO =
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
const ALGO = 'AES-256-GCM';
|
|
3
3
|
export const encrypt = (text, secret) => {
|
|
4
|
-
const key = crypto.createHash(
|
|
4
|
+
const key = crypto.createHash('sha256').update(secret).digest();
|
|
5
5
|
const iv = crypto.randomBytes(16);
|
|
6
6
|
const cipher = crypto.createCipheriv(ALGO, key, iv);
|
|
7
|
-
const encrypted = Buffer.concat([cipher.update(text,
|
|
8
|
-
return `${iv.toString(
|
|
7
|
+
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
|
|
8
|
+
return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
|
|
9
9
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import crypto from
|
|
1
|
+
import crypto from 'crypto';
|
|
2
2
|
/**
|
|
3
3
|
* Sign message using HMAC SHA-256
|
|
4
4
|
*/
|
|
5
5
|
export const hmacSign = (message, secret) => {
|
|
6
|
-
return crypto.createHmac(
|
|
6
|
+
return crypto.createHmac('sha256', secret).update(message).digest('hex');
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Verify HMAC signature
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { decrypt } from
|
|
2
|
-
export { encrypt } from
|
|
3
|
-
export { hmacSign, hmacVerify } from
|
|
4
|
-
export { randomToken, generateStrongPassword } from
|
|
5
|
-
export * from
|
|
1
|
+
export { decrypt } from './decrypt';
|
|
2
|
+
export { encrypt } from './encrypt';
|
|
3
|
+
export { hmacSign, hmacVerify } from './hmac';
|
|
4
|
+
export { randomToken, generateStrongPassword } from './random';
|
|
5
|
+
export * from './cryptoManager';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { decrypt } from
|
|
2
|
-
export { encrypt } from
|
|
3
|
-
export { hmacSign, hmacVerify } from
|
|
4
|
-
export { randomToken, generateStrongPassword } from
|
|
5
|
-
export * from
|
|
1
|
+
export { decrypt } from './decrypt';
|
|
2
|
+
export { encrypt } from './encrypt';
|
|
3
|
+
export { hmacSign, hmacVerify } from './hmac';
|
|
4
|
+
export { randomToken, generateStrongPassword } from './random';
|
|
5
|
+
export * from './cryptoManager';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import crypto from
|
|
1
|
+
import crypto from 'crypto';
|
|
2
2
|
/**
|
|
3
3
|
* Generate cryptographically secure random string
|
|
4
4
|
*/
|
|
5
5
|
export const randomToken = (length = 32) => {
|
|
6
|
-
return crypto.randomBytes(length).toString(
|
|
6
|
+
return crypto.randomBytes(length).toString('hex');
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Generate a strong random password
|
|
10
10
|
*/
|
|
11
11
|
export const generateStrongPassword = (length = 16) => {
|
|
12
|
-
return crypto.randomBytes(length).toString(
|
|
12
|
+
return crypto.randomBytes(length).toString('hex').slice(0, length);
|
|
13
13
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/jwt/decodeToken.ts
|
|
2
|
-
import { decode } from
|
|
2
|
+
import { decode } from 'jsonwebtoken';
|
|
3
3
|
/**
|
|
4
4
|
* Flexible decode
|
|
5
5
|
* Returns: null | string | JwtPayload
|
|
@@ -14,8 +14,8 @@ export function decodeToken(token) {
|
|
|
14
14
|
*/
|
|
15
15
|
export function decodeTokenStrict(token) {
|
|
16
16
|
const decoded = decode(token);
|
|
17
|
-
if (!decoded || typeof decoded ===
|
|
18
|
-
throw new Error(
|
|
17
|
+
if (!decoded || typeof decoded === 'string') {
|
|
18
|
+
throw new Error('Invalid JWT payload structure');
|
|
19
19
|
}
|
|
20
20
|
return decoded;
|
|
21
21
|
}
|
|
@@ -5,16 +5,16 @@ export function extractToken(sources) {
|
|
|
5
5
|
const { header, cookies, query, body, wsMessage } = sources;
|
|
6
6
|
// 1. Authorization: Bearer <token>
|
|
7
7
|
if (header) {
|
|
8
|
-
const parts = header.split(
|
|
9
|
-
if (parts.length === 2 && parts[0] ===
|
|
8
|
+
const parts = header.split(' ');
|
|
9
|
+
if (parts.length === 2 && parts[0] === 'Bearer')
|
|
10
10
|
return parts[1];
|
|
11
11
|
}
|
|
12
12
|
// 2. Cookies: token / accessToken
|
|
13
13
|
if (cookies) {
|
|
14
|
-
if (cookies[
|
|
15
|
-
return cookies[
|
|
16
|
-
if (cookies[
|
|
17
|
-
return cookies[
|
|
14
|
+
if (cookies['token'])
|
|
15
|
+
return cookies['token'];
|
|
16
|
+
if (cookies['accessToken'])
|
|
17
|
+
return cookies['accessToken'];
|
|
18
18
|
}
|
|
19
19
|
// 3. Query params: ?token=xxx
|
|
20
20
|
if (query?.token)
|
|
@@ -27,7 +27,7 @@ export function extractToken(sources) {
|
|
|
27
27
|
try {
|
|
28
28
|
let msg = wsMessage;
|
|
29
29
|
// If it's a JSON string → parse safely
|
|
30
|
-
if (typeof wsMessage ===
|
|
30
|
+
if (typeof wsMessage === 'string') {
|
|
31
31
|
msg = JSON.parse(wsMessage);
|
|
32
32
|
}
|
|
33
33
|
// Ensure msg is an object before property access
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Secret } from
|
|
2
|
-
import { RefreshToken, TokenPair } from
|
|
1
|
+
import { type Secret } from 'jsonwebtoken';
|
|
2
|
+
import type { RefreshToken, TokenPair } from './types';
|
|
3
3
|
export declare const generateTokens: (payload: Record<string, unknown>, accessSecret: Secret, refreshSecret: Secret, accessExpiry?: string | number, refreshExpiry?: string | number) => TokenPair;
|
|
4
4
|
export declare function rotateRefreshToken(oldToken: string, secret: Secret): RefreshToken;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { signToken } from
|
|
2
|
-
import { verifyToken } from
|
|
1
|
+
import { signToken } from './signToken';
|
|
2
|
+
import { verifyToken } from './verify';
|
|
3
3
|
// Helper function to create branded tokens
|
|
4
4
|
const createBrandedToken = (token, _brand) => {
|
|
5
5
|
return token;
|
|
6
6
|
};
|
|
7
|
-
export const generateTokens = (payload, accessSecret, refreshSecret, accessExpiry =
|
|
8
|
-
const accessToken = signToken(payload, accessSecret, accessExpiry, {
|
|
9
|
-
|
|
7
|
+
export const generateTokens = (payload, accessSecret, refreshSecret, accessExpiry = '15m', refreshExpiry = '7d') => {
|
|
8
|
+
const accessToken = signToken(payload, accessSecret, accessExpiry, {
|
|
9
|
+
algorithm: 'HS256',
|
|
10
|
+
});
|
|
11
|
+
const refreshToken = signToken(payload, refreshSecret, refreshExpiry, {
|
|
12
|
+
algorithm: 'HS256',
|
|
13
|
+
});
|
|
10
14
|
return {
|
|
11
15
|
accessToken: accessToken,
|
|
12
16
|
refreshToken: refreshToken,
|
|
@@ -14,12 +18,12 @@ export const generateTokens = (payload, accessSecret, refreshSecret, accessExpir
|
|
|
14
18
|
};
|
|
15
19
|
export function rotateRefreshToken(oldToken, secret) {
|
|
16
20
|
const decoded = verifyToken(oldToken, secret);
|
|
17
|
-
if (typeof decoded ===
|
|
18
|
-
throw new Error(
|
|
21
|
+
if (typeof decoded === 'string') {
|
|
22
|
+
throw new Error('Invalid token payload — expected JWT payload object');
|
|
19
23
|
}
|
|
20
24
|
const payload = { ...decoded };
|
|
21
25
|
delete payload.iat;
|
|
22
26
|
delete payload.exp;
|
|
23
|
-
const newToken = signToken(payload, secret,
|
|
27
|
+
const newToken = signToken(payload, secret, '7d');
|
|
24
28
|
return newToken;
|
|
25
29
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
1
|
+
export * from './decode';
|
|
2
|
+
export * from './extractToken';
|
|
3
|
+
export * from './generateTokens';
|
|
4
|
+
export * from './parseDuration';
|
|
5
|
+
export * from './signToken';
|
|
6
|
+
export * from './types';
|
|
7
|
+
export * from './validateToken';
|
|
8
|
+
export * from './verify';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
1
|
+
export * from './decode';
|
|
2
|
+
export * from './extractToken';
|
|
3
|
+
export * from './generateTokens';
|
|
4
|
+
export * from './parseDuration';
|
|
5
|
+
export * from './signToken';
|
|
6
|
+
export * from './types';
|
|
7
|
+
export * from './validateToken';
|
|
8
|
+
export * from './verify';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { JwtPayload, Secret } from
|
|
2
|
-
import {
|
|
1
|
+
import { type JwtPayload, type Secret } from 'jsonwebtoken';
|
|
2
|
+
import type { AccessToken, ITokenManager, JWTConfig, RefreshToken, TokenPair, TokenValidationOptions } from '../../interfaces/jwt.interface';
|
|
3
3
|
export declare class JWTManager implements ITokenManager {
|
|
4
4
|
private accessSecret;
|
|
5
5
|
private refreshSecret;
|
|
6
6
|
private accessExpiry;
|
|
7
7
|
private refreshExpiry;
|
|
8
8
|
private cache?;
|
|
9
|
+
private cacheTTL;
|
|
9
10
|
constructor(config: JWTConfig);
|
|
10
11
|
/**
|
|
11
12
|
* Generate both access and refresh tokens
|