@naman_deep_singh/security 1.3.2 → 1.4.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.
Files changed (52) hide show
  1. package/README.md +153 -355
  2. package/dist/cjs/core/crypto/cryptoManager.d.ts +5 -5
  3. package/dist/cjs/core/crypto/cryptoManager.js +42 -25
  4. package/dist/cjs/core/jwt/decode.js +4 -1
  5. package/dist/cjs/core/jwt/generateTokens.d.ts +1 -1
  6. package/dist/cjs/core/jwt/generateTokens.js +7 -4
  7. package/dist/cjs/core/jwt/jwtManager.d.ts +19 -43
  8. package/dist/cjs/core/jwt/jwtManager.js +72 -202
  9. package/dist/cjs/core/jwt/parseDuration.js +3 -2
  10. package/dist/cjs/core/jwt/signToken.js +2 -1
  11. package/dist/cjs/core/jwt/validateToken.d.ts +10 -7
  12. package/dist/cjs/core/jwt/validateToken.js +14 -11
  13. package/dist/cjs/core/jwt/verify.d.ts +9 -10
  14. package/dist/cjs/core/jwt/verify.js +57 -14
  15. package/dist/cjs/core/password/hash.js +4 -4
  16. package/dist/cjs/core/password/passwordManager.d.ts +2 -2
  17. package/dist/cjs/core/password/passwordManager.js +43 -82
  18. package/dist/cjs/core/password/strength.js +5 -5
  19. package/dist/cjs/core/password/utils.d.ts +12 -0
  20. package/dist/cjs/core/password/utils.js +16 -1
  21. package/dist/cjs/core/password/verify.js +5 -5
  22. package/dist/cjs/index.d.ts +2 -7
  23. package/dist/esm/core/crypto/cryptoManager.d.ts +5 -5
  24. package/dist/esm/core/crypto/cryptoManager.js +42 -25
  25. package/dist/esm/core/jwt/decode.js +4 -1
  26. package/dist/esm/core/jwt/generateTokens.d.ts +1 -1
  27. package/dist/esm/core/jwt/generateTokens.js +7 -4
  28. package/dist/esm/core/jwt/jwtManager.d.ts +19 -43
  29. package/dist/esm/core/jwt/jwtManager.js +73 -203
  30. package/dist/esm/core/jwt/parseDuration.js +3 -2
  31. package/dist/esm/core/jwt/signToken.js +2 -1
  32. package/dist/esm/core/jwt/validateToken.d.ts +10 -7
  33. package/dist/esm/core/jwt/validateToken.js +14 -11
  34. package/dist/esm/core/jwt/verify.d.ts +9 -10
  35. package/dist/esm/core/jwt/verify.js +55 -12
  36. package/dist/esm/core/password/hash.js +4 -4
  37. package/dist/esm/core/password/passwordManager.d.ts +2 -2
  38. package/dist/esm/core/password/passwordManager.js +43 -82
  39. package/dist/esm/core/password/strength.js +5 -5
  40. package/dist/esm/core/password/utils.d.ts +12 -0
  41. package/dist/esm/core/password/utils.js +16 -1
  42. package/dist/esm/core/password/verify.js +5 -5
  43. package/dist/esm/index.d.ts +2 -7
  44. package/dist/types/core/crypto/cryptoManager.d.ts +5 -5
  45. package/dist/types/core/jwt/generateTokens.d.ts +1 -1
  46. package/dist/types/core/jwt/jwtManager.d.ts +19 -43
  47. package/dist/types/core/jwt/validateToken.d.ts +10 -7
  48. package/dist/types/core/jwt/verify.d.ts +9 -10
  49. package/dist/types/core/password/passwordManager.d.ts +2 -2
  50. package/dist/types/core/password/utils.d.ts +12 -0
  51. package/dist/types/index.d.ts +2 -7
  52. package/package.json +2 -2
@@ -27,25 +27,20 @@ class PasswordManager {
27
27
  async hash(password, salt) {
28
28
  try {
29
29
  (0, utils_1.ensureValidPassword)(password);
30
- // Validate password meets basic requirements
31
30
  this.validate(password);
32
31
  const saltRounds = this.defaultConfig.saltRounds;
33
- let passwordSalt = salt;
34
- if (!passwordSalt) {
35
- passwordSalt = await bcryptjs_1.default.genSalt(saltRounds);
32
+ let finalSalt = salt;
33
+ if (!finalSalt) {
34
+ finalSalt = await bcryptjs_1.default.genSalt(saltRounds);
36
35
  }
37
- const hash = await bcryptjs_1.default.hash(password, passwordSalt);
38
- return {
39
- hash,
40
- salt: passwordSalt,
41
- };
36
+ const hash = await bcryptjs_1.default.hash(password, finalSalt);
37
+ return { hash, salt: finalSalt };
42
38
  }
43
39
  catch (error) {
44
- if (error instanceof errors_utils_1.BadRequestError ||
45
- error instanceof errors_utils_1.ValidationError) {
40
+ if (error instanceof errors_utils_1.BadRequestError || error instanceof errors_utils_1.ValidationError) {
46
41
  throw error;
47
42
  }
48
- throw new errors_utils_1.BadRequestError('Failed to hash password');
43
+ throw new errors_utils_1.BadRequestError({ message: 'Failed to hash password' }, error instanceof Error ? error : undefined);
49
44
  }
50
45
  }
51
46
  /**
@@ -53,19 +48,12 @@ class PasswordManager {
53
48
  */
54
49
  async verify(password, hash, salt) {
55
50
  try {
56
- if (!password || !hash || !salt) {
51
+ if (!password || !hash || !salt)
57
52
  return false;
58
- }
59
- // First verify with the provided salt
60
- const isValid = await bcryptjs_1.default.compare(password, hash);
61
- // If invalid and different salt was used, try regenerating hash with new salt
62
- if (!isValid && salt !== this.defaultConfig.saltRounds?.toString()) {
63
- const newHash = await bcryptjs_1.default.hash(password, salt);
64
- return newHash === hash;
65
- }
66
- return isValid;
53
+ // bcrypt compare works directly with hash
54
+ return await bcryptjs_1.default.compare(password, hash);
67
55
  }
68
- catch (error) {
56
+ catch {
69
57
  return false;
70
58
  }
71
59
  }
@@ -75,7 +63,7 @@ class PasswordManager {
75
63
  generate(length = 16, options = {}) {
76
64
  const config = { ...this.defaultConfig, ...options };
77
65
  if (length < config.minLength || length > config.maxLength) {
78
- throw new errors_utils_1.ValidationError(`Password length must be between ${config.minLength} and ${config.maxLength}`);
66
+ throw new errors_utils_1.ValidationError({ message: `Password length must be between ${config.minLength} and ${config.maxLength}` });
79
67
  }
80
68
  let charset = 'abcdefghijklmnopqrstuvwxyz';
81
69
  if (config.requireUppercase)
@@ -84,24 +72,20 @@ class PasswordManager {
84
72
  charset += '0123456789';
85
73
  if (config.requireSpecialChars)
86
74
  charset += '!@#$%^&*()_+-=[]{}|;:,.<>?';
87
- let password = '';
88
75
  const randomBytes = crypto_1.default.randomBytes(length);
76
+ let password = '';
89
77
  for (let i = 0; i < length; i++) {
90
78
  password += charset[randomBytes[i] % charset.length];
91
79
  }
92
- // Ensure all requirements are met
93
- if (config.requireUppercase && !/[A-Z]/.test(password)) {
80
+ // Ensure requirements
81
+ if (config.requireUppercase && !/[A-Z]/.test(password))
94
82
  password = password.replace(/[a-z]/, 'A');
95
- }
96
- if (config.requireLowercase && !/[a-z]/.test(password)) {
83
+ if (config.requireLowercase && !/[a-z]/.test(password))
97
84
  password = password.replace(/[A-Z]/, 'a');
98
- }
99
- if (config.requireNumbers && !/[0-9]/.test(password)) {
85
+ if (config.requireNumbers && !/[0-9]/.test(password))
100
86
  password = password.replace(/[A-Za-z]/, '0');
101
- }
102
- if (config.requireSpecialChars && !/[^A-Za-z0-9]/.test(password)) {
87
+ if (config.requireSpecialChars && !/[^A-Za-z0-9]/.test(password))
103
88
  password = password.replace(/[A-Za-z0-9]/, '!');
104
- }
105
89
  return password;
106
90
  }
107
91
  /**
@@ -110,45 +94,27 @@ class PasswordManager {
110
94
  validate(password, config = {}) {
111
95
  const finalConfig = { ...this.defaultConfig, ...config };
112
96
  const errors = [];
113
- // Basic validation
114
- if (!password || typeof password !== 'string') {
97
+ if (!password || typeof password !== 'string')
115
98
  errors.push('Password must be a non-empty string');
116
- }
117
- // Length validation
118
- if (password.length < finalConfig.minLength) {
119
- errors.push(`Password must be at least ${finalConfig.minLength} characters long`);
120
- }
121
- if (password.length > finalConfig.maxLength) {
99
+ if (password.length < finalConfig.minLength)
100
+ errors.push(`Password must be at least ${finalConfig.minLength} characters`);
101
+ if (password.length > finalConfig.maxLength)
122
102
  errors.push(`Password must not exceed ${finalConfig.maxLength} characters`);
123
- }
124
- // Complexity requirements
125
- if (finalConfig.requireUppercase && !/[A-Z]/.test(password)) {
103
+ if (finalConfig.requireUppercase && !/[A-Z]/.test(password))
126
104
  errors.push('Password must contain at least one uppercase letter');
127
- }
128
- if (finalConfig.requireLowercase && !/[a-z]/.test(password)) {
105
+ if (finalConfig.requireLowercase && !/[a-z]/.test(password))
129
106
  errors.push('Password must contain at least one lowercase letter');
130
- }
131
- if (finalConfig.requireNumbers && !/[0-9]/.test(password)) {
107
+ if (finalConfig.requireNumbers && !/[0-9]/.test(password))
132
108
  errors.push('Password must contain at least one number');
133
- }
134
- if (finalConfig.requireSpecialChars && !/[^A-Za-z0-9]/.test(password)) {
109
+ if (finalConfig.requireSpecialChars && !/[^A-Za-z0-9]/.test(password))
135
110
  errors.push('Password must contain at least one special character');
136
- }
137
- // Custom rules
138
111
  if (finalConfig.customRules) {
139
112
  finalConfig.customRules.forEach((rule) => {
140
- if (!rule.test(password)) {
113
+ if (!rule.test(password))
141
114
  errors.push(rule.message);
142
- }
143
115
  });
144
116
  }
145
- const strength = this.checkStrength(password);
146
- const isValid = errors.length === 0;
147
- return {
148
- isValid,
149
- errors,
150
- strength,
151
- };
117
+ return { isValid: errors.length === 0, errors, strength: this.checkStrength(password) };
152
118
  }
153
119
  /**
154
120
  * Check password strength
@@ -158,14 +124,20 @@ class PasswordManager {
158
124
  let score = 0;
159
125
  const feedback = [];
160
126
  const suggestions = [];
161
- // Length scoring
162
- if (password.length >= 8)
127
+ if (entropy < 28) {
128
+ feedback.push('Password is easy to guess');
129
+ suggestions.push('Use more unique characters and length');
130
+ }
131
+ else if (entropy < 36)
163
132
  score++;
133
+ else if (entropy < 60)
134
+ score += 2;
135
+ else
136
+ score += 3;
164
137
  if (password.length >= 12)
165
138
  score++;
166
139
  if (password.length >= 16)
167
140
  score++;
168
- // Character variety scoring
169
141
  if (/[a-z]/.test(password))
170
142
  score++;
171
143
  if (/[A-Z]/.test(password))
@@ -174,10 +146,9 @@ class PasswordManager {
174
146
  score++;
175
147
  if (/[^A-Za-z0-9]/.test(password))
176
148
  score++;
177
- // Common patterns deduction
178
149
  if (/^[A-Za-z]+$/.test(password)) {
179
150
  score--;
180
- feedback.push('Consider adding numbers and symbols');
151
+ feedback.push('Consider adding numbers or symbols');
181
152
  }
182
153
  if (/^[0-9]+$/.test(password)) {
183
154
  score -= 2;
@@ -191,13 +162,11 @@ class PasswordManager {
191
162
  score--;
192
163
  feedback.push('Avoid sequential patterns');
193
164
  }
194
- // Common passwords check
195
165
  const commonPasswords = ['password', '123456', 'qwerty', 'admin', 'letmein'];
196
166
  if (commonPasswords.some((common) => password.toLowerCase().includes(common))) {
197
167
  score = 0;
198
168
  feedback.push('Avoid common passwords');
199
169
  }
200
- // Clamp score and determine label
201
170
  score = Math.max(0, Math.min(4, score));
202
171
  let label;
203
172
  switch (score) {
@@ -211,7 +180,7 @@ class PasswordManager {
211
180
  break;
212
181
  case 2:
213
182
  label = 'fair';
214
- suggestions.push('Consider adding more length or character types');
183
+ suggestions.push('Consider increasing length or randomness');
215
184
  break;
216
185
  case 3:
217
186
  label = 'good';
@@ -221,22 +190,14 @@ class PasswordManager {
221
190
  label = 'strong';
222
191
  suggestions.push('Your password is very secure');
223
192
  break;
224
- default:
225
- label = 'very-weak';
193
+ default: label = 'very-weak';
226
194
  }
227
- return {
228
- score,
229
- label,
230
- feedback,
231
- suggestions,
232
- };
195
+ return { score, label, feedback, suggestions };
233
196
  }
234
197
  /**
235
- * Check if password hash needs upgrade (different salt rounds)
198
+ * Check if password hash needs upgrade (saltRounds change)
236
199
  */
237
- needsUpgrade(hash, currentConfig) {
238
- // Simple heuristic: if the hash doesn't match current salt rounds pattern
239
- // In practice, you'd need to store the salt rounds with the hash
200
+ needsUpgrade(_hash, _currentConfig) {
240
201
  return false;
241
202
  }
242
203
  }
@@ -4,18 +4,18 @@ exports.isPasswordStrong = void 0;
4
4
  const errors_utils_1 = require("@naman_deep_singh/errors-utils");
5
5
  const isPasswordStrong = (password, options = {}) => {
6
6
  if (!password)
7
- throw new errors_utils_1.BadRequestError('Invalid password provided');
7
+ throw new errors_utils_1.BadRequestError({ message: 'Invalid password provided' });
8
8
  const { minLength = 8, requireUppercase = true, requireLowercase = true, requireNumbers = true, requireSymbols = false, } = 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('Password must include uppercase letters');
12
+ throw new errors_utils_1.ValidationError({ message: 'Password must include uppercase letters' });
13
13
  if (requireLowercase && !/[a-z]/.test(password))
14
- throw new errors_utils_1.ValidationError('Password must include lowercase letters');
14
+ throw new errors_utils_1.ValidationError({ message: 'Password must include lowercase letters' });
15
15
  if (requireNumbers && !/[0-9]/.test(password))
16
- throw new errors_utils_1.ValidationError('Password must include numbers');
16
+ throw new errors_utils_1.ValidationError({ message: 'Password must include numbers' });
17
17
  if (requireSymbols && !/[^A-Za-z0-9]/.test(password))
18
- throw new errors_utils_1.ValidationError('Password must include symbols');
18
+ throw new errors_utils_1.ValidationError({ message: 'Password must include symbols' });
19
19
  return true;
20
20
  };
21
21
  exports.isPasswordStrong = isPasswordStrong;
@@ -1,4 +1,16 @@
1
+ /**
2
+ * Ensure password is a valid non-empty string
3
+ */
1
4
  export declare function ensureValidPassword(password: string): void;
5
+ /**
6
+ * Timing-safe comparison between two strings
7
+ */
2
8
  export declare function safeCompare(a: string, b: string): boolean;
9
+ /**
10
+ * Estimate password entropy based on character pool
11
+ */
3
12
  export declare function estimatePasswordEntropy(password: string): number;
13
+ /**
14
+ * Normalize password string to a consistent form
15
+ */
4
16
  export declare function normalizePassword(password: string): string;
@@ -9,11 +9,17 @@ exports.estimatePasswordEntropy = estimatePasswordEntropy;
9
9
  exports.normalizePassword = normalizePassword;
10
10
  const crypto_1 = __importDefault(require("crypto"));
11
11
  const errors_utils_1 = require("@naman_deep_singh/errors-utils");
12
+ /**
13
+ * Ensure password is a valid non-empty string
14
+ */
12
15
  function ensureValidPassword(password) {
13
16
  if (!password || typeof password !== 'string') {
14
- throw new errors_utils_1.BadRequestError('Invalid password provided');
17
+ throw new errors_utils_1.BadRequestError({ message: 'Invalid password provided' });
15
18
  }
16
19
  }
20
+ /**
21
+ * Timing-safe comparison between two strings
22
+ */
17
23
  function safeCompare(a, b) {
18
24
  const bufA = Buffer.from(a);
19
25
  const bufB = Buffer.from(b);
@@ -21,6 +27,9 @@ function safeCompare(a, b) {
21
27
  return false;
22
28
  return crypto_1.default.timingSafeEqual(bufA, bufB);
23
29
  }
30
+ /**
31
+ * Estimate password entropy based on character pool
32
+ */
24
33
  function estimatePasswordEntropy(password) {
25
34
  let pool = 0;
26
35
  if (/[a-z]/.test(password))
@@ -31,8 +40,14 @@ function estimatePasswordEntropy(password) {
31
40
  pool += 10;
32
41
  if (/[^A-Za-z0-9]/.test(password))
33
42
  pool += 32;
43
+ // If no characters matched, fallback to 1 to avoid log2(0)
44
+ if (pool === 0)
45
+ pool = 1;
34
46
  return password.length * Math.log2(pool);
35
47
  }
48
+ /**
49
+ * Normalize password string to a consistent form
50
+ */
36
51
  function normalizePassword(password) {
37
52
  return password.normalize('NFKC');
38
53
  }
@@ -15,11 +15,11 @@ const verifyPassword = async (password, hash) => {
15
15
  try {
16
16
  const result = await bcryptjs_1.default.compare(password, hash);
17
17
  if (!result)
18
- throw new errors_utils_1.UnauthorizedError('Password verification failed');
18
+ throw new errors_utils_1.UnauthorizedError({ message: 'Password verification failed' });
19
19
  return result;
20
20
  }
21
21
  catch {
22
- throw new errors_utils_1.UnauthorizedError('Password verification failed');
22
+ throw new errors_utils_1.UnauthorizedError({ message: 'Password verification failed' });
23
23
  }
24
24
  };
25
25
  exports.verifyPassword = verifyPassword;
@@ -33,11 +33,11 @@ const verifyPasswordSync = (password, hash) => {
33
33
  try {
34
34
  const result = bcryptjs_1.default.compareSync(password, hash);
35
35
  if (!result)
36
- throw new errors_utils_1.UnauthorizedError('Password verification failed');
36
+ throw new errors_utils_1.UnauthorizedError({ message: 'Password verification failed' });
37
37
  return result;
38
38
  }
39
- catch (error) {
40
- throw new errors_utils_1.UnauthorizedError('Password verification failed');
39
+ catch (_error) {
40
+ throw new errors_utils_1.UnauthorizedError({ message: 'Password verification failed' });
41
41
  }
42
42
  };
43
43
  exports.verifyPasswordSync = verifyPasswordSync;
@@ -21,16 +21,11 @@ declare const _default: {
21
21
  generateTokens: (payload: Record<string, unknown>, accessSecret: import("node_modules/@types/jsonwebtoken").Secret, refreshSecret: import("node_modules/@types/jsonwebtoken").Secret, accessExpiry?: string | number, refreshExpiry?: string | number) => JWTUtils.TokenPair;
22
22
  parseDuration(input: string | number): number;
23
23
  signToken: (payload: Record<string, unknown>, secret: import("node_modules/@types/jsonwebtoken").Secret, expiresIn?: string | number, options?: import("node_modules/@types/jsonwebtoken").SignOptions) => string;
24
- validateTokenPayload(payload: Record<string, unknown>, rules?: JWTUtils.TokenRequirements): {
25
- valid: true;
26
- } | {
27
- valid: false;
28
- error: string;
29
- };
24
+ validateTokenPayload(payload: Record<string, unknown>, rules?: JWTUtils.TokenRequirements): void;
30
25
  isTokenExpired(payload: import("node_modules/@types/jsonwebtoken").JwtPayload): boolean;
31
26
  verifyToken: (token: string, secret: import("node_modules/@types/jsonwebtoken").Secret) => string | import("node_modules/@types/jsonwebtoken").JwtPayload;
32
- safeVerifyToken: (token: string, secret: import("node_modules/@types/jsonwebtoken").Secret) => JWTUtils.VerificationResult;
33
27
  verifyTokenWithOptions: (token: string, secret: import("node_modules/@types/jsonwebtoken").Secret, options?: import("node_modules/@types/jsonwebtoken").VerifyOptions) => string | import("node_modules/@types/jsonwebtoken").JwtPayload;
28
+ safeVerifyToken: (token: string, secret: import("node_modules/@types/jsonwebtoken").Secret) => JWTUtils.VerificationResult;
34
29
  safeVerifyTokenWithOptions: (token: string, secret: import("node_modules/@types/jsonwebtoken").Secret, options?: import("node_modules/@types/jsonwebtoken").VerifyOptions) => JWTUtils.VerificationResult;
35
30
  hashPasswordWithPepper(password: string, pepper: string): Promise<string>;
36
31
  hashPasswordWithPepperSync(password: string, pepper: string): string;
@@ -24,7 +24,7 @@ export declare class CryptoManager {
24
24
  /**
25
25
  * Encrypt data using the default or specified algorithm
26
26
  */
27
- encrypt(plaintext: string, key: string, options?: {
27
+ encrypt(plaintext: string, key: string, _options?: {
28
28
  algorithm?: string;
29
29
  encoding?: BufferEncoding;
30
30
  iv?: string;
@@ -32,7 +32,7 @@ export declare class CryptoManager {
32
32
  /**
33
33
  * Decrypt data using the default or specified algorithm
34
34
  */
35
- decrypt(encryptedData: string, key: string, options?: {
35
+ decrypt(encryptedData: string, key: string, _options?: {
36
36
  algorithm?: string;
37
37
  encoding?: BufferEncoding;
38
38
  iv?: string;
@@ -40,18 +40,18 @@ export declare class CryptoManager {
40
40
  /**
41
41
  * Generate HMAC signature
42
42
  */
43
- generateHmac(data: string, secret: string, options?: {
43
+ generateHmac(data: string, secret: string, _options?: {
44
44
  algorithm?: string;
45
45
  encoding?: BufferEncoding;
46
46
  }): string;
47
47
  /**
48
48
  * Generate cryptographically secure random bytes
49
49
  */
50
- generateSecureRandom(length: number, encoding?: BufferEncoding): string;
50
+ generateSecureRandom(length: number, _encoding?: BufferEncoding): string;
51
51
  /**
52
52
  * Verify HMAC signature
53
53
  */
54
- verifyHmac(data: string, secret: string, signature: string, options?: {
54
+ verifyHmac(data: string, secret: string, signature: string, _options?: {
55
55
  algorithm?: string;
56
56
  encoding?: BufferEncoding;
57
57
  }): boolean;
@@ -1,3 +1,4 @@
1
+ import { InternalServerError } from '@naman_deep_singh/errors-utils';
1
2
  import { decrypt as functionalDecrypt, encrypt as functionalEncrypt, hmacSign as functionalHmacSign, hmacVerify as functionalHmacVerify, randomToken as functionalRandomToken, } from './index';
2
3
  /**
3
4
  * Default configuration
@@ -30,23 +31,33 @@ export class CryptoManager {
30
31
  /**
31
32
  * Encrypt data using the default or specified algorithm
32
33
  */
33
- encrypt(plaintext, key, options) {
34
- // For now, use the basic encrypt function
35
- // TODO: Enhance to support different algorithms and options
36
- return functionalEncrypt(plaintext, key);
34
+ encrypt(plaintext, key, _options) {
35
+ try {
36
+ return functionalEncrypt(plaintext, key);
37
+ }
38
+ catch (err) {
39
+ throw new InternalServerError(undefined, {
40
+ message: 'Encryption failed',
41
+ }, err instanceof Error ? err : undefined);
42
+ }
37
43
  }
38
44
  /**
39
45
  * Decrypt data using the default or specified algorithm
40
46
  */
41
- decrypt(encryptedData, key, options) {
42
- // For now, use the basic decrypt function
43
- // TODO: Enhance to support different algorithms and options
44
- return functionalDecrypt(encryptedData, key);
47
+ decrypt(encryptedData, key, _options) {
48
+ try {
49
+ return functionalDecrypt(encryptedData, key);
50
+ }
51
+ catch (err) {
52
+ throw new InternalServerError(undefined, {
53
+ message: 'Decryption failed',
54
+ }, err instanceof Error ? err : undefined);
55
+ }
45
56
  }
46
57
  /**
47
58
  * Generate HMAC signature
48
59
  */
49
- generateHmac(data, secret, options) {
60
+ generateHmac(data, secret, _options) {
50
61
  // Use the basic HMAC sign function for now
51
62
  // TODO: Add support for different algorithms
52
63
  return functionalHmacSign(data, secret);
@@ -54,14 +65,14 @@ export class CryptoManager {
54
65
  /**
55
66
  * Generate cryptographically secure random bytes
56
67
  */
57
- generateSecureRandom(length, encoding = 'hex') {
68
+ generateSecureRandom(length, _encoding = 'hex') {
58
69
  // Use the basic random token function
59
70
  return functionalRandomToken(length);
60
71
  }
61
72
  /**
62
73
  * Verify HMAC signature
63
74
  */
64
- verifyHmac(data, secret, signature, options) {
75
+ verifyHmac(data, secret, signature, _options) {
65
76
  // Use the basic HMAC verify function
66
77
  return functionalHmacVerify(data, secret, signature);
67
78
  }
@@ -73,7 +84,9 @@ export class CryptoManager {
73
84
  const crypto = require('crypto');
74
85
  crypto.pbkdf2(password, salt, iterations, keyLength, 'sha256', (err, derivedKey) => {
75
86
  if (err) {
76
- reject(err);
87
+ reject(new InternalServerError(undefined, {
88
+ message: 'Key derivation failed',
89
+ }, err instanceof Error ? err : undefined));
77
90
  }
78
91
  else {
79
92
  resolve(derivedKey.toString('hex'));
@@ -99,7 +112,7 @@ export class CryptoManager {
99
112
  * Generate a secure key pair for asymmetric encryption
100
113
  */
101
114
  generateKeyPair(options) {
102
- return new Promise((resolve, reject) => {
115
+ return new Promise((resolve, _reject) => {
103
116
  const crypto = require('crypto');
104
117
  const keyPair = crypto.generateKeyPairSync('rsa', {
105
118
  modulusLength: options?.modulusLength || 2048,
@@ -119,7 +132,7 @@ export class CryptoManager {
119
132
  * Encrypt data using RSA public key
120
133
  */
121
134
  rsaEncrypt(data, publicKey) {
122
- return new Promise((resolve, reject) => {
135
+ return new Promise((resolve, _reject) => {
123
136
  const crypto = require('crypto');
124
137
  const buffer = Buffer.from(data, 'utf8');
125
138
  const encrypted = crypto.publicEncrypt(publicKey, buffer);
@@ -130,7 +143,7 @@ export class CryptoManager {
130
143
  * Decrypt data using RSA private key
131
144
  */
132
145
  rsaDecrypt(encryptedData, privateKey) {
133
- return new Promise((resolve, reject) => {
146
+ return new Promise((resolve, _reject) => {
134
147
  const crypto = require('crypto');
135
148
  const buffer = Buffer.from(encryptedData, 'base64');
136
149
  const decrypted = crypto.privateDecrypt(privateKey, buffer);
@@ -143,15 +156,17 @@ export class CryptoManager {
143
156
  rsaSign(data, privateKey, algorithm = 'sha256') {
144
157
  return new Promise((resolve, reject) => {
145
158
  const crypto = require('crypto');
146
- const sign = crypto.createSign(algorithm);
147
- sign.update(data);
148
- sign.end();
149
159
  try {
160
+ const sign = crypto.createSign(algorithm);
161
+ sign.update(data);
162
+ sign.end();
150
163
  const signature = sign.sign(privateKey, 'base64');
151
164
  resolve(signature);
152
165
  }
153
- catch (error) {
154
- reject(error);
166
+ catch (err) {
167
+ reject(new InternalServerError(undefined, {
168
+ message: 'RSA signing failed',
169
+ }, err instanceof Error ? err : undefined));
155
170
  }
156
171
  });
157
172
  }
@@ -161,15 +176,17 @@ export class CryptoManager {
161
176
  rsaVerify(data, signature, publicKey, algorithm = 'sha256') {
162
177
  return new Promise((resolve, reject) => {
163
178
  const crypto = require('crypto');
164
- const verify = crypto.createVerify(algorithm);
165
- verify.update(data);
166
- verify.end();
167
179
  try {
180
+ const verify = crypto.createVerify(algorithm);
181
+ verify.update(data);
182
+ verify.end();
168
183
  const isValid = verify.verify(publicKey, signature, 'base64');
169
184
  resolve(isValid);
170
185
  }
171
- catch (error) {
172
- reject(error);
186
+ catch (err) {
187
+ reject(new InternalServerError(undefined, {
188
+ message: 'RSA verification failed',
189
+ }, err instanceof Error ? err : undefined));
173
190
  }
174
191
  });
175
192
  }
@@ -1,5 +1,6 @@
1
1
  // src/jwt/decodeToken.ts
2
2
  import { decode } from 'jsonwebtoken';
3
+ import { BadRequestError } from '@naman_deep_singh/errors-utils';
3
4
  /**
4
5
  * Flexible decode
5
6
  * Returns: null | string | JwtPayload
@@ -15,7 +16,9 @@ export function decodeToken(token) {
15
16
  export function decodeTokenStrict(token) {
16
17
  const decoded = decode(token);
17
18
  if (!decoded || typeof decoded === 'string') {
18
- throw new Error('Invalid JWT payload structure');
19
+ throw new BadRequestError({
20
+ message: 'Invalid JWT payload structure',
21
+ });
19
22
  }
20
23
  return decoded;
21
24
  }
@@ -1,4 +1,4 @@
1
- import { type Secret } from 'jsonwebtoken';
1
+ import type { Secret } from 'jsonwebtoken';
2
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,9 +1,10 @@
1
1
  import { signToken } from './signToken';
2
2
  import { verifyToken } from './verify';
3
+ import { TokenMalformedError } from '@naman_deep_singh/errors-utils';
3
4
  // Helper function to create branded tokens
4
- const createBrandedToken = (token, _brand) => {
5
- return token;
6
- };
5
+ /* const createBrandedToken = <T extends string>(token: string, _brand: T): T => {
6
+ return token as T
7
+ } */
7
8
  export const generateTokens = (payload, accessSecret, refreshSecret, accessExpiry = '15m', refreshExpiry = '7d') => {
8
9
  const accessToken = signToken(payload, accessSecret, accessExpiry, {
9
10
  algorithm: 'HS256',
@@ -19,7 +20,9 @@ export const generateTokens = (payload, accessSecret, refreshSecret, accessExpir
19
20
  export function rotateRefreshToken(oldToken, secret) {
20
21
  const decoded = verifyToken(oldToken, secret);
21
22
  if (typeof decoded === 'string') {
22
- throw new Error('Invalid token payload — expected JWT payload object');
23
+ throw new TokenMalformedError({
24
+ message: 'Invalid token payload — expected JWT payload object',
25
+ });
23
26
  }
24
27
  const payload = { ...decoded };
25
28
  delete payload.iat;