@naman_deep_singh/security 1.3.3 → 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 (46) hide show
  1. package/README.md +153 -355
  2. package/dist/cjs/core/crypto/cryptoManager.js +34 -17
  3. package/dist/cjs/core/jwt/decode.js +4 -1
  4. package/dist/cjs/core/jwt/generateTokens.js +4 -1
  5. package/dist/cjs/core/jwt/jwtManager.d.ts +19 -43
  6. package/dist/cjs/core/jwt/jwtManager.js +72 -206
  7. package/dist/cjs/core/jwt/parseDuration.js +3 -2
  8. package/dist/cjs/core/jwt/signToken.js +2 -1
  9. package/dist/cjs/core/jwt/validateToken.d.ts +10 -7
  10. package/dist/cjs/core/jwt/validateToken.js +14 -11
  11. package/dist/cjs/core/jwt/verify.d.ts +9 -10
  12. package/dist/cjs/core/jwt/verify.js +57 -14
  13. package/dist/cjs/core/password/hash.js +2 -2
  14. package/dist/cjs/core/password/passwordManager.d.ts +1 -1
  15. package/dist/cjs/core/password/passwordManager.js +35 -87
  16. package/dist/cjs/core/password/strength.js +5 -5
  17. package/dist/cjs/core/password/utils.d.ts +12 -0
  18. package/dist/cjs/core/password/utils.js +16 -1
  19. package/dist/cjs/core/password/verify.js +4 -4
  20. package/dist/cjs/index.d.ts +2 -7
  21. package/dist/esm/core/crypto/cryptoManager.js +34 -17
  22. package/dist/esm/core/jwt/decode.js +4 -1
  23. package/dist/esm/core/jwt/generateTokens.js +4 -1
  24. package/dist/esm/core/jwt/jwtManager.d.ts +19 -43
  25. package/dist/esm/core/jwt/jwtManager.js +73 -207
  26. package/dist/esm/core/jwt/parseDuration.js +3 -2
  27. package/dist/esm/core/jwt/signToken.js +2 -1
  28. package/dist/esm/core/jwt/validateToken.d.ts +10 -7
  29. package/dist/esm/core/jwt/validateToken.js +14 -11
  30. package/dist/esm/core/jwt/verify.d.ts +9 -10
  31. package/dist/esm/core/jwt/verify.js +55 -12
  32. package/dist/esm/core/password/hash.js +2 -2
  33. package/dist/esm/core/password/passwordManager.d.ts +1 -1
  34. package/dist/esm/core/password/passwordManager.js +35 -87
  35. package/dist/esm/core/password/strength.js +5 -5
  36. package/dist/esm/core/password/utils.d.ts +12 -0
  37. package/dist/esm/core/password/utils.js +16 -1
  38. package/dist/esm/core/password/verify.js +4 -4
  39. package/dist/esm/index.d.ts +2 -7
  40. package/dist/types/core/jwt/jwtManager.d.ts +19 -43
  41. package/dist/types/core/jwt/validateToken.d.ts +10 -7
  42. package/dist/types/core/jwt/verify.d.ts +9 -10
  43. package/dist/types/core/password/passwordManager.d.ts +1 -1
  44. package/dist/types/core/password/utils.d.ts +12 -0
  45. package/dist/types/index.d.ts +2 -7
  46. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.cryptoManager = exports.createCryptoManager = exports.CryptoManager = void 0;
4
+ const errors_utils_1 = require("@naman_deep_singh/errors-utils");
4
5
  const index_1 = require("./index");
5
6
  /**
6
7
  * Default configuration
@@ -34,17 +35,27 @@ class CryptoManager {
34
35
  * Encrypt data using the default or specified algorithm
35
36
  */
36
37
  encrypt(plaintext, key, _options) {
37
- // For now, use the basic encrypt function
38
- // TODO: Enhance to support different algorithms and options
39
- return (0, index_1.encrypt)(plaintext, key);
38
+ try {
39
+ return (0, index_1.encrypt)(plaintext, key);
40
+ }
41
+ catch (err) {
42
+ throw new errors_utils_1.InternalServerError(undefined, {
43
+ message: 'Encryption failed',
44
+ }, err instanceof Error ? err : undefined);
45
+ }
40
46
  }
41
47
  /**
42
48
  * Decrypt data using the default or specified algorithm
43
49
  */
44
50
  decrypt(encryptedData, key, _options) {
45
- // For now, use the basic decrypt function
46
- // TODO: Enhance to support different algorithms and options
47
- return (0, index_1.decrypt)(encryptedData, key);
51
+ try {
52
+ return (0, index_1.decrypt)(encryptedData, key);
53
+ }
54
+ catch (err) {
55
+ throw new errors_utils_1.InternalServerError(undefined, {
56
+ message: 'Decryption failed',
57
+ }, err instanceof Error ? err : undefined);
58
+ }
48
59
  }
49
60
  /**
50
61
  * Generate HMAC signature
@@ -76,7 +87,9 @@ class CryptoManager {
76
87
  const crypto = require('crypto');
77
88
  crypto.pbkdf2(password, salt, iterations, keyLength, 'sha256', (err, derivedKey) => {
78
89
  if (err) {
79
- reject(err);
90
+ reject(new errors_utils_1.InternalServerError(undefined, {
91
+ message: 'Key derivation failed',
92
+ }, err instanceof Error ? err : undefined));
80
93
  }
81
94
  else {
82
95
  resolve(derivedKey.toString('hex'));
@@ -146,15 +159,17 @@ class CryptoManager {
146
159
  rsaSign(data, privateKey, algorithm = 'sha256') {
147
160
  return new Promise((resolve, reject) => {
148
161
  const crypto = require('crypto');
149
- const sign = crypto.createSign(algorithm);
150
- sign.update(data);
151
- sign.end();
152
162
  try {
163
+ const sign = crypto.createSign(algorithm);
164
+ sign.update(data);
165
+ sign.end();
153
166
  const signature = sign.sign(privateKey, 'base64');
154
167
  resolve(signature);
155
168
  }
156
- catch (error) {
157
- reject(error);
169
+ catch (err) {
170
+ reject(new errors_utils_1.InternalServerError(undefined, {
171
+ message: 'RSA signing failed',
172
+ }, err instanceof Error ? err : undefined));
158
173
  }
159
174
  });
160
175
  }
@@ -164,15 +179,17 @@ class CryptoManager {
164
179
  rsaVerify(data, signature, publicKey, algorithm = 'sha256') {
165
180
  return new Promise((resolve, reject) => {
166
181
  const crypto = require('crypto');
167
- const verify = crypto.createVerify(algorithm);
168
- verify.update(data);
169
- verify.end();
170
182
  try {
183
+ const verify = crypto.createVerify(algorithm);
184
+ verify.update(data);
185
+ verify.end();
171
186
  const isValid = verify.verify(publicKey, signature, 'base64');
172
187
  resolve(isValid);
173
188
  }
174
- catch (error) {
175
- reject(error);
189
+ catch (err) {
190
+ reject(new errors_utils_1.InternalServerError(undefined, {
191
+ message: 'RSA verification failed',
192
+ }, err instanceof Error ? err : undefined));
176
193
  }
177
194
  });
178
195
  }
@@ -4,6 +4,7 @@ exports.decodeToken = decodeToken;
4
4
  exports.decodeTokenStrict = decodeTokenStrict;
5
5
  // src/jwt/decodeToken.ts
6
6
  const jsonwebtoken_1 = require("jsonwebtoken");
7
+ const errors_utils_1 = require("@naman_deep_singh/errors-utils");
7
8
  /**
8
9
  * Flexible decode
9
10
  * Returns: null | string | JwtPayload
@@ -19,7 +20,9 @@ function decodeToken(token) {
19
20
  function decodeTokenStrict(token) {
20
21
  const decoded = (0, jsonwebtoken_1.decode)(token);
21
22
  if (!decoded || typeof decoded === 'string') {
22
- throw new Error('Invalid JWT payload structure');
23
+ throw new errors_utils_1.BadRequestError({
24
+ message: 'Invalid JWT payload structure',
25
+ });
23
26
  }
24
27
  return decoded;
25
28
  }
@@ -4,6 +4,7 @@ exports.generateTokens = void 0;
4
4
  exports.rotateRefreshToken = rotateRefreshToken;
5
5
  const signToken_1 = require("./signToken");
6
6
  const verify_1 = require("./verify");
7
+ const errors_utils_1 = require("@naman_deep_singh/errors-utils");
7
8
  // Helper function to create branded tokens
8
9
  /* const createBrandedToken = <T extends string>(token: string, _brand: T): T => {
9
10
  return token as T
@@ -24,7 +25,9 @@ exports.generateTokens = generateTokens;
24
25
  function rotateRefreshToken(oldToken, secret) {
25
26
  const decoded = (0, verify_1.verifyToken)(oldToken, secret);
26
27
  if (typeof decoded === 'string') {
27
- throw new Error('Invalid token payload — expected JWT payload object');
28
+ throw new errors_utils_1.TokenMalformedError({
29
+ message: 'Invalid token payload — expected JWT payload object',
30
+ });
28
31
  }
29
32
  const payload = { ...decoded };
30
33
  delete payload.iat;
@@ -1,5 +1,5 @@
1
1
  import { type JwtPayload, type Secret } from 'jsonwebtoken';
2
- import type { AccessToken, ITokenManager, JWTConfig, RefreshToken, TokenPair, TokenValidationOptions } from '../../interfaces/jwt.interface';
2
+ import type { AccessToken, ITokenManager, JWTConfig, RefreshToken, TokenPair } from '../../interfaces/jwt.interface';
3
3
  export declare class JWTManager implements ITokenManager {
4
4
  private accessSecret;
5
5
  private refreshSecret;
@@ -8,60 +8,36 @@ export declare class JWTManager implements ITokenManager {
8
8
  private cache?;
9
9
  private cacheTTL;
10
10
  constructor(config: JWTConfig);
11
- /**
12
- * Generate both access and refresh tokens
13
- */
11
+ /** Generate both access and refresh tokens */
14
12
  generateTokens(payload: Record<string, unknown>): Promise<TokenPair>;
15
- /**
16
- * Generate access token
17
- */
13
+ /** Generate access token */
18
14
  generateAccessToken(payload: Record<string, unknown>): Promise<AccessToken>;
19
- /**
20
- * Generate refresh token
21
- */
15
+ /** Generate refresh token */
22
16
  generateRefreshToken(payload: Record<string, unknown>): Promise<RefreshToken>;
23
- /**
24
- * Verify access token
25
- */
26
- verifyAccessToken(token: string): Promise<JwtPayload | string>;
27
- /**
28
- * Verify refresh token
29
- */
30
- verifyRefreshToken(token: string): Promise<JwtPayload | string>;
31
- /**
32
- * Decode token without verification
33
- */
17
+ /** Verify access token */
18
+ verifyAccessToken(token: string): Promise<JwtPayload>;
19
+ /** Verify refresh token */
20
+ verifyRefreshToken(token: string): Promise<JwtPayload>;
21
+ /** Decode token without verification */
34
22
  decodeToken(token: string, complete?: boolean): JwtPayload | string | null;
35
- /**
36
- * Extract token from Authorization header
37
- */
23
+ /** Extract token from Authorization header */
38
24
  extractTokenFromHeader(authHeader: string): string | null;
39
- /**
40
- * Validate token without throwing exceptions
41
- */
42
- validateToken(token: string, secret: Secret, _options?: TokenValidationOptions): boolean;
43
- /**
44
- * Rotate refresh token
45
- */
25
+ /** Validate token without throwing exceptions */
26
+ validateToken(token: string, secret: Secret): boolean;
27
+ /** Rotate refresh token */
46
28
  rotateRefreshToken(oldToken: string): Promise<RefreshToken>;
47
- /**
48
- * Check if token is expired
49
- */
29
+ /** Check if token is expired */
50
30
  isTokenExpired(token: string): boolean;
51
- /**
52
- * Get token expiration date
53
- */
31
+ /** Get token expiration date */
54
32
  getTokenExpiration(token: string): Date | null;
55
- /**
56
- * Clear token cache
57
- */
33
+ /** Clear token cache */
58
34
  clearCache(): void;
59
- /**
60
- * Get cache statistics
61
- */
35
+ /** Get cache statistics */
62
36
  getCacheStats(): {
63
37
  size: number;
64
38
  maxSize: number;
65
39
  } | null;
40
+ /** Private helper methods */
66
41
  private validatePayload;
42
+ private verifyTokenWithCache;
67
43
  }
@@ -15,289 +15,155 @@ class JWTManager {
15
15
  this.refreshSecret = config.refreshSecret;
16
16
  this.accessExpiry = config.accessExpiry || '15m';
17
17
  this.refreshExpiry = config.refreshExpiry || '7d';
18
- this.cacheTTL = 5 * 60 * 1000; // 5 minutes default TTL
18
+ this.cacheTTL = 5 * 60 * 1000; // 5 minutes
19
19
  if (config.enableCaching) {
20
20
  this.cache = new js_extensions_1.LRUCache(config.maxCacheSize || 100);
21
21
  }
22
22
  }
23
- /**
24
- * Generate both access and refresh tokens
25
- */
23
+ /** Generate both access and refresh tokens */
26
24
  async generateTokens(payload) {
27
25
  try {
28
26
  this.validatePayload(payload);
29
27
  const accessToken = await this.generateAccessToken(payload);
30
28
  const refreshToken = await this.generateRefreshToken(payload);
31
- return {
32
- accessToken,
33
- refreshToken,
34
- };
29
+ return { accessToken, refreshToken };
35
30
  }
36
31
  catch (error) {
37
- if (error instanceof errors_utils_1.BadRequestError ||
38
- error instanceof errors_utils_1.ValidationError) {
32
+ if (error instanceof errors_utils_1.BadRequestError || error instanceof errors_utils_1.ValidationError)
39
33
  throw error;
40
- }
41
- throw new errors_utils_1.BadRequestError('Failed to generate tokens');
34
+ throw new errors_utils_1.BadRequestError({ message: 'Failed to generate tokens' }, error instanceof Error ? error : undefined);
42
35
  }
43
36
  }
44
- /**
45
- * Generate access token
46
- */
37
+ /** Generate access token */
47
38
  async generateAccessToken(payload) {
48
39
  try {
49
40
  this.validatePayload(payload);
50
- const token = (0, signToken_1.signToken)(payload, this.accessSecret, this.accessExpiry, {
51
- algorithm: 'HS256',
52
- });
41
+ const token = (0, signToken_1.signToken)(payload, this.accessSecret, this.accessExpiry, { algorithm: 'HS256' });
53
42
  return token;
54
43
  }
55
44
  catch (error) {
56
- if (error instanceof errors_utils_1.BadRequestError ||
57
- error instanceof errors_utils_1.ValidationError) {
45
+ if (error instanceof errors_utils_1.BadRequestError || error instanceof errors_utils_1.ValidationError)
58
46
  throw error;
59
- }
60
- throw new errors_utils_1.BadRequestError('Failed to generate access token');
47
+ throw new errors_utils_1.BadRequestError({ message: 'Failed to generate access token' }, error instanceof Error ? error : undefined);
61
48
  }
62
49
  }
63
- /**
64
- * Generate refresh token
65
- */
50
+ /** Generate refresh token */
66
51
  async generateRefreshToken(payload) {
67
52
  try {
68
53
  this.validatePayload(payload);
69
- const token = (0, signToken_1.signToken)(payload, this.refreshSecret, this.refreshExpiry, {
70
- algorithm: 'HS256',
71
- });
54
+ const token = (0, signToken_1.signToken)(payload, this.refreshSecret, this.refreshExpiry, { algorithm: 'HS256' });
72
55
  return token;
73
56
  }
74
57
  catch (error) {
75
- if (error instanceof errors_utils_1.BadRequestError ||
76
- error instanceof errors_utils_1.ValidationError) {
58
+ if (error instanceof errors_utils_1.BadRequestError || error instanceof errors_utils_1.ValidationError)
77
59
  throw error;
78
- }
79
- throw new errors_utils_1.BadRequestError('Failed to generate refresh token');
60
+ throw new errors_utils_1.BadRequestError({ message: 'Failed to generate refresh token' }, error instanceof Error ? error : undefined);
80
61
  }
81
62
  }
82
- /**
83
- * Verify access token
84
- */
63
+ /** Verify access token */
85
64
  async verifyAccessToken(token) {
86
- try {
87
- if (!token || typeof token !== 'string') {
88
- throw new errors_utils_1.ValidationError('Access token must be a non-empty string');
89
- }
90
- const cacheKey = `access_${token}`;
91
- if (this.cache) {
92
- const cached = this.cache.get(cacheKey);
93
- if (cached && Date.now() - cached.timestamp <= this.cacheTTL) {
94
- if (!cached.valid) {
95
- throw new errors_utils_1.UnauthorizedError('Access token is invalid or expired');
96
- }
97
- return cached.payload;
98
- }
99
- }
100
- const decoded = (0, verify_1.verifyToken)(token, this.accessSecret);
101
- if (this.cache) {
102
- this.cache.set(cacheKey, {
103
- valid: true,
104
- payload: decoded,
105
- timestamp: Date.now(),
106
- });
107
- }
108
- return decoded;
109
- }
110
- catch (error) {
111
- if (error instanceof errors_utils_1.ValidationError ||
112
- error instanceof errors_utils_1.UnauthorizedError) {
113
- throw error;
114
- }
115
- if (error instanceof Error && error.name === 'TokenExpiredError') {
116
- throw new errors_utils_1.UnauthorizedError('Access token has expired');
117
- }
118
- if (error instanceof Error && error.name === 'JsonWebTokenError') {
119
- throw new errors_utils_1.UnauthorizedError('Access token is invalid');
120
- }
121
- throw new errors_utils_1.UnauthorizedError('Failed to verify access token');
122
- }
65
+ return this.verifyTokenWithCache(token, this.accessSecret, 'access');
123
66
  }
124
- /**
125
- * Verify refresh token
126
- */
67
+ /** Verify refresh token */
127
68
  async verifyRefreshToken(token) {
128
- try {
129
- if (!token || typeof token !== 'string') {
130
- throw new errors_utils_1.ValidationError('Refresh token must be a non-empty string');
131
- }
132
- const cacheKey = `refresh_${token}`;
133
- if (this.cache) {
134
- const cached = this.cache.get(cacheKey);
135
- if (cached) {
136
- if (!cached.valid) {
137
- throw new errors_utils_1.UnauthorizedError('Refresh token is invalid or expired');
138
- }
139
- return cached.payload;
140
- }
141
- }
142
- const decoded = (0, verify_1.verifyToken)(token, this.refreshSecret);
143
- if (this.cache) {
144
- this.cache.set(cacheKey, {
145
- valid: true,
146
- payload: decoded,
147
- timestamp: Date.now(),
148
- });
149
- }
150
- return decoded;
151
- }
152
- catch (error) {
153
- if (error instanceof errors_utils_1.ValidationError ||
154
- error instanceof errors_utils_1.UnauthorizedError) {
155
- throw error;
156
- }
157
- if (error instanceof Error && error.name === 'TokenExpiredError') {
158
- throw new errors_utils_1.UnauthorizedError('Refresh token has expired');
159
- }
160
- if (error instanceof Error && error.name === 'JsonWebTokenError') {
161
- throw new errors_utils_1.UnauthorizedError('Refresh token is invalid');
162
- }
163
- throw new errors_utils_1.UnauthorizedError('Failed to verify refresh token');
164
- }
69
+ return this.verifyTokenWithCache(token, this.refreshSecret, 'refresh');
165
70
  }
166
- /**
167
- * Decode token without verification
168
- */
71
+ /** Decode token without verification */
169
72
  decodeToken(token, complete = false) {
170
- try {
171
- if (!token || typeof token !== 'string') {
172
- throw new errors_utils_1.ValidationError('Token must be a non-empty string');
173
- }
174
- return jsonwebtoken_1.default.decode(token, { complete });
175
- }
176
- catch (error) {
177
- if (error instanceof errors_utils_1.ValidationError) {
178
- throw error;
179
- }
73
+ if (!token || typeof token !== 'string')
180
74
  return null;
181
- }
75
+ return jsonwebtoken_1.default.decode(token, { complete });
182
76
  }
183
- /**
184
- * Extract token from Authorization header
185
- */
77
+ /** Extract token from Authorization header */
186
78
  extractTokenFromHeader(authHeader) {
187
- try {
188
- if (!authHeader || typeof authHeader !== 'string') {
189
- return null;
190
- }
191
- const parts = authHeader.split(' ');
192
- if (parts.length !== 2 || parts[0] !== 'Bearer') {
193
- return null;
194
- }
195
- return parts[1];
196
- }
197
- catch {
79
+ if (!authHeader || typeof authHeader !== 'string')
198
80
  return null;
199
- }
81
+ const parts = authHeader.split(' ');
82
+ if (parts.length !== 2 || parts[0] !== 'Bearer')
83
+ return null;
84
+ return parts[1];
200
85
  }
201
- /**
202
- * Validate token without throwing exceptions
203
- */
204
- validateToken(token, secret, _options = {}) {
205
- try {
206
- if (!token || typeof token !== 'string') {
207
- return false;
208
- }
209
- const result = (0, verify_1.safeVerifyToken)(token, secret);
210
- return result.valid;
211
- }
212
- catch {
86
+ /** Validate token without throwing exceptions */
87
+ validateToken(token, secret) {
88
+ if (!token || typeof token !== 'string')
213
89
  return false;
214
- }
90
+ return (0, verify_1.safeVerifyToken)(token, secret).valid;
215
91
  }
216
- /**
217
- * Rotate refresh token
218
- */
92
+ /** Rotate refresh token */
219
93
  async rotateRefreshToken(oldToken) {
220
- try {
221
- if (!oldToken || typeof oldToken !== 'string') {
222
- throw new errors_utils_1.ValidationError('Old refresh token must be a non-empty string');
223
- }
224
- const decoded = await this.verifyRefreshToken(oldToken);
225
- if (typeof decoded === 'string') {
226
- throw new errors_utils_1.ValidationError('Invalid token payload — expected JWT payload object');
227
- }
228
- // Create new payload without issued/expired timestamps
229
- const payload = { ...decoded };
230
- delete payload.iat;
231
- delete payload.exp;
232
- // Generate new refresh token
233
- const newToken = (0, signToken_1.signToken)(payload, this.refreshSecret, this.refreshExpiry);
234
- return newToken;
235
- }
236
- catch (error) {
237
- if (error instanceof errors_utils_1.ValidationError ||
238
- error instanceof errors_utils_1.UnauthorizedError) {
239
- throw error;
240
- }
241
- throw new errors_utils_1.BadRequestError('Failed to rotate refresh token');
242
- }
94
+ if (!oldToken || typeof oldToken !== 'string') {
95
+ throw new errors_utils_1.ValidationError({ message: 'Old refresh token must be a non-empty string' });
96
+ }
97
+ const decoded = await this.verifyRefreshToken(oldToken);
98
+ const payload = { ...decoded };
99
+ delete payload.iat;
100
+ delete payload.exp;
101
+ const newToken = (0, signToken_1.signToken)(payload, this.refreshSecret, this.refreshExpiry);
102
+ return newToken;
243
103
  }
244
- /**
245
- * Check if token is expired
246
- */
104
+ /** Check if token is expired */
247
105
  isTokenExpired(token) {
248
106
  try {
249
107
  const decoded = this.decodeToken(token);
250
- if (!decoded || !decoded.exp) {
108
+ if (!decoded || !decoded.exp)
251
109
  return true;
252
- }
253
- const currentTime = Math.floor(Date.now() / 1000);
254
- return decoded.exp < currentTime;
110
+ return decoded.exp < Math.floor(Date.now() / 1000);
255
111
  }
256
112
  catch {
257
113
  return true;
258
114
  }
259
115
  }
260
- /**
261
- * Get token expiration date
262
- */
116
+ /** Get token expiration date */
263
117
  getTokenExpiration(token) {
264
118
  try {
265
119
  const decoded = this.decodeToken(token);
266
- if (!decoded || !decoded.exp) {
120
+ if (!decoded || !decoded.exp)
267
121
  return null;
268
- }
269
122
  return new Date(decoded.exp * 1000);
270
123
  }
271
124
  catch {
272
125
  return null;
273
126
  }
274
127
  }
275
- /**
276
- * Clear token cache
277
- */
128
+ /** Clear token cache */
278
129
  clearCache() {
279
130
  this.cache?.clear();
280
131
  }
281
- /**
282
- * Get cache statistics
283
- */
132
+ /** Get cache statistics */
284
133
  getCacheStats() {
285
134
  if (!this.cache)
286
135
  return null;
287
- // Note: LRUCache doesn't expose internal size, so we return maxSize only
288
- return {
289
- size: -1, // Size not available from LRUCache
290
- maxSize: this.cache.maxSize,
291
- };
136
+ return { size: -1, maxSize: this.cache.maxSize };
292
137
  }
293
- // Private helper methods
138
+ /** Private helper methods */
294
139
  validatePayload(payload) {
295
140
  if (!payload || typeof payload !== 'object') {
296
- throw new errors_utils_1.ValidationError('Payload must be a non-null object');
141
+ throw new errors_utils_1.ValidationError({ message: 'Payload must be a non-null object' });
297
142
  }
298
143
  if (Object.keys(payload).length === 0) {
299
- throw new errors_utils_1.ValidationError('Payload cannot be empty');
144
+ throw new errors_utils_1.ValidationError({ message: 'Payload cannot be empty' });
300
145
  }
301
146
  }
147
+ async verifyTokenWithCache(token, secret, type) {
148
+ if (!token || typeof token !== 'string') {
149
+ throw new errors_utils_1.ValidationError({ message: `${type} token must be a non-empty string` });
150
+ }
151
+ const cacheKey = `${type}_${token}`;
152
+ if (this.cache) {
153
+ const cached = this.cache.get(cacheKey);
154
+ if (cached && Date.now() - cached.timestamp <= this.cacheTTL) {
155
+ if (!cached.valid)
156
+ throw new errors_utils_1.UnauthorizedError({ message: `${type} token is invalid or expired` });
157
+ return cached.payload;
158
+ }
159
+ }
160
+ const { valid, payload, error } = (0, verify_1.safeVerifyToken)(token, secret);
161
+ if (!valid || !payload || typeof payload === 'string') {
162
+ this.cache?.set(cacheKey, { valid: false, payload: {}, timestamp: Date.now() });
163
+ throw new errors_utils_1.UnauthorizedError({ message: `${type} token is invalid or expired`, cause: error });
164
+ }
165
+ this.cache?.set(cacheKey, { valid: true, payload, timestamp: Date.now() });
166
+ return payload;
167
+ }
302
168
  }
303
169
  exports.JWTManager = JWTManager;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseDuration = parseDuration;
4
+ const errors_utils_1 = require("@naman_deep_singh/errors-utils");
4
5
  const TIME_UNITS = {
5
6
  s: 1,
6
7
  m: 60,
@@ -18,12 +19,12 @@ function parseDuration(input) {
18
19
  const value = Number.parseInt(match[1], 10);
19
20
  const unit = match[2].toLowerCase();
20
21
  if (!TIME_UNITS[unit]) {
21
- throw new Error(`Invalid time unit: ${unit}`);
22
+ throw new errors_utils_1.ValidationError({ message: `Invalid time unit: ${unit}` });
22
23
  }
23
24
  totalSeconds += value * TIME_UNITS[unit];
24
25
  }
25
26
  if (totalSeconds === 0) {
26
- throw new Error(`Invalid expiry format: "${input}"`);
27
+ throw new errors_utils_1.ValidationError({ message: `Invalid expiry format: "${input}"` });
27
28
  }
28
29
  return totalSeconds;
29
30
  }
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.signToken = void 0;
4
4
  const jsonwebtoken_1 = require("jsonwebtoken");
5
5
  const parseDuration_1 = require("./parseDuration");
6
+ const errors_utils_1 = require("@naman_deep_singh/errors-utils");
6
7
  function getExpiryTimestamp(seconds) {
7
8
  return Math.floor(Date.now() / 1000) + seconds;
8
9
  }
9
10
  const signToken = (payload, secret, expiresIn = '1h', options = {}) => {
10
11
  const seconds = (0, parseDuration_1.parseDuration)(expiresIn);
11
12
  if (!seconds || seconds < 10) {
12
- throw new Error('Token expiry too small');
13
+ throw new errors_utils_1.ValidationError({ message: 'Token expiry too small' });
13
14
  }
14
15
  const tokenPayload = {
15
16
  ...payload,
@@ -1,13 +1,16 @@
1
- import type { JwtPayload } from 'node_modules/@types/jsonwebtoken';
1
+ import type { JwtPayload } from 'jsonwebtoken';
2
2
  export interface TokenRequirements {
3
3
  requiredFields?: string[];
4
4
  forbiddenFields?: string[];
5
5
  validateTypes?: Record<string, 'string' | 'number' | 'boolean'>;
6
6
  }
7
- export declare function validateTokenPayload(payload: Record<string, unknown>, rules?: TokenRequirements): {
8
- valid: true;
9
- } | {
10
- valid: false;
11
- error: string;
12
- };
7
+ /**
8
+ * Validates a JWT payload according to the provided rules.
9
+ * Throws ValidationError if validation fails.
10
+ */
11
+ export declare function validateTokenPayload(payload: Record<string, unknown>, rules?: TokenRequirements): void;
12
+ /**
13
+ * Checks if a JWT payload is expired.
14
+ * Returns true if expired or missing 'exp'.
15
+ */
13
16
  export declare function isTokenExpired(payload: JwtPayload): boolean;