@naman_deep_singh/security 1.5.1 → 1.6.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/README.md +3 -3
- package/dist/cjs/core/crypto/cryptoManager.js +6 -6
- package/dist/cjs/core/jwt/decode.js +2 -2
- package/dist/cjs/core/jwt/generateTokens.js +2 -2
- package/dist/cjs/core/jwt/jwtManager.js +15 -15
- package/dist/cjs/core/jwt/parseDuration.js +3 -3
- package/dist/cjs/core/jwt/signToken.js +2 -2
- package/dist/cjs/core/jwt/validateToken.js +4 -4
- package/dist/cjs/core/jwt/verify.js +13 -13
- package/dist/cjs/core/password/hash.js +3 -3
- package/dist/cjs/core/password/passwordManager.js +5 -5
- package/dist/cjs/core/password/strength.js +7 -7
- package/dist/cjs/core/password/utils.js +2 -2
- package/dist/cjs/core/password/verify.js +5 -5
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +5 -5
- package/dist/esm/core/crypto/cryptoManager.js +1 -1
- package/dist/esm/core/jwt/decode.js +1 -1
- package/dist/esm/core/jwt/generateTokens.js +1 -1
- package/dist/esm/core/jwt/jwtManager.js +2 -2
- package/dist/esm/core/jwt/parseDuration.js +1 -1
- package/dist/esm/core/jwt/signToken.js +1 -1
- package/dist/esm/core/jwt/validateToken.js +1 -1
- package/dist/esm/core/jwt/verify.js +1 -1
- package/dist/esm/core/password/hash.js +1 -1
- package/dist/esm/core/password/passwordManager.js +1 -1
- package/dist/esm/core/password/strength.js +1 -1
- package/dist/esm/core/password/utils.js +1 -1
- package/dist/esm/core/password/verify.js +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
```bash
|
|
2
2
|
@naman_deep_singh/security
|
|
3
3
|
|
|
4
|
-
Version: 1.
|
|
4
|
+
Version: 1.6.0
|
|
5
5
|
|
|
6
6
|
A complete, lightweight security toolkit for Node.js & TypeScript providing:
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ A complete, lightweight security toolkit for Node.js & TypeScript providing:
|
|
|
13
13
|
🧰 Robust token extraction (Headers, Cookies, Query, Body, WebSocket)
|
|
14
14
|
🧩 Safe & strict JWT decode utilities
|
|
15
15
|
🔒 AES-256-GCM encryption/decryption with HMAC and random utilities
|
|
16
|
-
🚨 Standardized error handling with @naman_deep_singh/errors
|
|
16
|
+
🚨 Standardized error handling with @naman_deep_singh/errors
|
|
17
17
|
|
|
18
18
|
✔ Fully typed with TypeScript
|
|
19
19
|
✔ Branded token types for compile-time safety (AccessToken/RefreshToken)
|
|
@@ -220,7 +220,7 @@ const randomHex = cryptoManager.generateRandomHex(32);
|
|
|
220
220
|
|
|
221
221
|
🚨 Error Handling
|
|
222
222
|
|
|
223
|
-
This package uses standardized errors from @naman_deep_singh/errors
|
|
223
|
+
This package uses standardized errors from @naman_deep_singh/errors:
|
|
224
224
|
|
|
225
225
|
import {
|
|
226
226
|
BadRequestError,
|
|
@@ -1,7 +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
|
|
4
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
5
5
|
const index_1 = require("./index");
|
|
6
6
|
/**
|
|
7
7
|
* Default configuration
|
|
@@ -39,7 +39,7 @@ class CryptoManager {
|
|
|
39
39
|
return (0, index_1.encrypt)(plaintext, key);
|
|
40
40
|
}
|
|
41
41
|
catch (error) {
|
|
42
|
-
throw new
|
|
42
|
+
throw new errors_1.CryptoIntegrityError({
|
|
43
43
|
reason: 'Encryption failed',
|
|
44
44
|
}, error instanceof Error ? error : undefined);
|
|
45
45
|
}
|
|
@@ -52,7 +52,7 @@ class CryptoManager {
|
|
|
52
52
|
return (0, index_1.decrypt)(encryptedData, key);
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
55
|
-
throw new
|
|
55
|
+
throw new errors_1.CryptoIntegrityError({
|
|
56
56
|
reason: 'Decryption failed',
|
|
57
57
|
}, error instanceof Error ? error : undefined);
|
|
58
58
|
}
|
|
@@ -87,7 +87,7 @@ class CryptoManager {
|
|
|
87
87
|
const crypto = require('crypto');
|
|
88
88
|
crypto.pbkdf2(password, salt, iterations, keyLength, 'sha256', (error, derivedKey) => {
|
|
89
89
|
if (error) {
|
|
90
|
-
reject(new
|
|
90
|
+
reject(new errors_1.CryptoIntegrityError({
|
|
91
91
|
reason: 'Key derivation failed',
|
|
92
92
|
}, error instanceof Error ? error : undefined));
|
|
93
93
|
}
|
|
@@ -167,7 +167,7 @@ class CryptoManager {
|
|
|
167
167
|
resolve(signature);
|
|
168
168
|
}
|
|
169
169
|
catch (error) {
|
|
170
|
-
reject(new
|
|
170
|
+
reject(new errors_1.CryptoIntegrityError({
|
|
171
171
|
reason: 'RSA signing failed',
|
|
172
172
|
}, error instanceof Error ? error : undefined));
|
|
173
173
|
}
|
|
@@ -187,7 +187,7 @@ class CryptoManager {
|
|
|
187
187
|
resolve(isValid);
|
|
188
188
|
}
|
|
189
189
|
catch (error) {
|
|
190
|
-
reject(new
|
|
190
|
+
reject(new errors_1.CryptoIntegrityError({
|
|
191
191
|
reason: 'RSA verification failed',
|
|
192
192
|
}, error instanceof Error ? error : undefined));
|
|
193
193
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.decodeToken = decodeToken;
|
|
4
4
|
exports.decodeTokenStrict = decodeTokenStrict;
|
|
5
|
-
const
|
|
5
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
6
6
|
// src/jwt/decodeToken.ts
|
|
7
7
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
8
8
|
/**
|
|
@@ -20,7 +20,7 @@ function decodeToken(token) {
|
|
|
20
20
|
function decodeTokenStrict(token) {
|
|
21
21
|
const decoded = (0, jsonwebtoken_1.decode)(token);
|
|
22
22
|
if (!decoded || typeof decoded === 'string') {
|
|
23
|
-
throw new
|
|
23
|
+
throw new errors_1.BadRequestError({
|
|
24
24
|
reason: 'Invalid JWT payload structure',
|
|
25
25
|
});
|
|
26
26
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateTokens = void 0;
|
|
4
4
|
exports.rotateRefreshToken = rotateRefreshToken;
|
|
5
|
-
const
|
|
5
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
6
6
|
const signToken_1 = require("./signToken");
|
|
7
7
|
const verify_1 = require("./verify");
|
|
8
8
|
// Helper function to create branded tokens
|
|
@@ -25,7 +25,7 @@ exports.generateTokens = generateTokens;
|
|
|
25
25
|
function rotateRefreshToken(oldToken, secret) {
|
|
26
26
|
const decoded = (0, verify_1.verifyToken)(oldToken, secret);
|
|
27
27
|
if (typeof decoded === 'string') {
|
|
28
|
-
throw new
|
|
28
|
+
throw new errors_1.TokenMalformedError({
|
|
29
29
|
reason: 'Invalid token payload — expected JWT payload object',
|
|
30
30
|
});
|
|
31
31
|
}
|
|
@@ -7,8 +7,8 @@ exports.JWTManager = void 0;
|
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
8
|
const signToken_1 = require("./signToken");
|
|
9
9
|
const verify_1 = require("./verify");
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
11
|
+
const utils_1 = require("@naman_deep_singh/utils");
|
|
12
12
|
class JWTManager {
|
|
13
13
|
constructor(config) {
|
|
14
14
|
this.accessSecret = config.accessSecret;
|
|
@@ -17,7 +17,7 @@ class JWTManager {
|
|
|
17
17
|
this.refreshExpiry = config.refreshExpiry || '7d';
|
|
18
18
|
this.cacheTTL = 5 * 60 * 1000; // 5 minutes
|
|
19
19
|
if (config.enableCaching) {
|
|
20
|
-
this.cache = new
|
|
20
|
+
this.cache = new utils_1.LRUCache(config.maxCacheSize || 100);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
/** Generate both access and refresh tokens */
|
|
@@ -29,9 +29,9 @@ class JWTManager {
|
|
|
29
29
|
return { accessToken, refreshToken };
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
|
-
if (error instanceof
|
|
32
|
+
if (error instanceof errors_1.BadRequestError || error instanceof errors_1.ValidationError)
|
|
33
33
|
throw error;
|
|
34
|
-
throw new
|
|
34
|
+
throw new errors_1.BadRequestError({ reason: 'Failed to generate tokens' }, error instanceof Error ? error : undefined);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
/** Generate access token */
|
|
@@ -44,9 +44,9 @@ class JWTManager {
|
|
|
44
44
|
return token;
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
47
|
-
if (error instanceof
|
|
47
|
+
if (error instanceof errors_1.BadRequestError || error instanceof errors_1.ValidationError)
|
|
48
48
|
throw error;
|
|
49
|
-
throw new
|
|
49
|
+
throw new errors_1.BadRequestError({ reason: 'Failed to generate access token' }, error instanceof Error ? error : undefined);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
/** Generate refresh token */
|
|
@@ -59,9 +59,9 @@ class JWTManager {
|
|
|
59
59
|
return token;
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
|
-
if (error instanceof
|
|
62
|
+
if (error instanceof errors_1.BadRequestError || error instanceof errors_1.ValidationError)
|
|
63
63
|
throw error;
|
|
64
|
-
throw new
|
|
64
|
+
throw new errors_1.BadRequestError({ reason: 'Failed to generate refresh token' }, error instanceof Error ? error : undefined);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
/** Verify access token */
|
|
@@ -96,7 +96,7 @@ class JWTManager {
|
|
|
96
96
|
/** Rotate refresh token */
|
|
97
97
|
async rotateRefreshToken(oldToken) {
|
|
98
98
|
if (!oldToken || typeof oldToken !== 'string') {
|
|
99
|
-
throw new
|
|
99
|
+
throw new errors_1.ValidationError({
|
|
100
100
|
reason: 'Old refresh token must be a non-empty string',
|
|
101
101
|
});
|
|
102
102
|
}
|
|
@@ -144,17 +144,17 @@ class JWTManager {
|
|
|
144
144
|
/** Private helper methods */
|
|
145
145
|
validatePayload(payload) {
|
|
146
146
|
if (!payload || typeof payload !== 'object') {
|
|
147
|
-
throw new
|
|
147
|
+
throw new errors_1.ValidationError({
|
|
148
148
|
reason: 'Payload must be a non-null object',
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
if (Object.keys(payload).length === 0) {
|
|
152
|
-
throw new
|
|
152
|
+
throw new errors_1.ValidationError({ reason: 'Payload cannot be empty' });
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
async verifyTokenWithCache(token, secret, type) {
|
|
156
156
|
if (!token || typeof token !== 'string') {
|
|
157
|
-
throw new
|
|
157
|
+
throw new errors_1.ValidationError({
|
|
158
158
|
reason: `${type} token must be a non-empty string`,
|
|
159
159
|
});
|
|
160
160
|
}
|
|
@@ -163,7 +163,7 @@ class JWTManager {
|
|
|
163
163
|
const cached = this.cache.get(cacheKey);
|
|
164
164
|
if (cached && Date.now() - cached.timestamp <= this.cacheTTL) {
|
|
165
165
|
if (!cached.valid)
|
|
166
|
-
throw new
|
|
166
|
+
throw new errors_1.UnauthorizedError({
|
|
167
167
|
reason: `${type} token is invalid or expired`,
|
|
168
168
|
});
|
|
169
169
|
return cached.payload;
|
|
@@ -176,7 +176,7 @@ class JWTManager {
|
|
|
176
176
|
payload: {},
|
|
177
177
|
timestamp: Date.now(),
|
|
178
178
|
});
|
|
179
|
-
throw new
|
|
179
|
+
throw new errors_1.UnauthorizedError({
|
|
180
180
|
reason: `${type} token is invalid or expired`,
|
|
181
181
|
cause: error,
|
|
182
182
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseDuration = parseDuration;
|
|
4
|
-
const
|
|
4
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
5
5
|
const TIME_UNITS = {
|
|
6
6
|
s: 1,
|
|
7
7
|
m: 60,
|
|
@@ -19,12 +19,12 @@ function parseDuration(input) {
|
|
|
19
19
|
const value = Number.parseInt(match[1], 10);
|
|
20
20
|
const unit = match[2].toLowerCase();
|
|
21
21
|
if (!TIME_UNITS[unit]) {
|
|
22
|
-
throw new
|
|
22
|
+
throw new errors_1.ValidationError({ reason: `Invalid time unit: ${unit}` });
|
|
23
23
|
}
|
|
24
24
|
totalSeconds += value * TIME_UNITS[unit];
|
|
25
25
|
}
|
|
26
26
|
if (totalSeconds === 0) {
|
|
27
|
-
throw new
|
|
27
|
+
throw new errors_1.ValidationError({ reason: `Invalid expiry format: "${input}"` });
|
|
28
28
|
}
|
|
29
29
|
return totalSeconds;
|
|
30
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.signToken = void 0;
|
|
4
|
-
const
|
|
4
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
5
5
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
6
6
|
const parseDuration_1 = require("./parseDuration");
|
|
7
7
|
function getExpiryTimestamp(seconds) {
|
|
@@ -10,7 +10,7 @@ function getExpiryTimestamp(seconds) {
|
|
|
10
10
|
const signToken = (payload, secret, expiresIn = '1h', options = {}) => {
|
|
11
11
|
const seconds = (0, parseDuration_1.parseDuration)(expiresIn);
|
|
12
12
|
if (!seconds || seconds < 10) {
|
|
13
|
-
throw new
|
|
13
|
+
throw new errors_1.ValidationError({ reason: 'Token expiry too small' });
|
|
14
14
|
}
|
|
15
15
|
const tokenPayload = {
|
|
16
16
|
...payload,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateTokenPayload = validateTokenPayload;
|
|
4
4
|
exports.isTokenExpired = isTokenExpired;
|
|
5
|
-
const
|
|
5
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
6
6
|
/**
|
|
7
7
|
* Validates a JWT payload according to the provided rules.
|
|
8
8
|
* Throws ValidationError if validation fails.
|
|
@@ -12,7 +12,7 @@ function validateTokenPayload(payload, rules = { requiredFields: ['exp', 'iat']
|
|
|
12
12
|
// 1. Required fields
|
|
13
13
|
for (const field of requiredFields) {
|
|
14
14
|
if (!(field in payload)) {
|
|
15
|
-
throw new
|
|
15
|
+
throw new errors_1.ValidationError({
|
|
16
16
|
reason: `Missing required field: ${field}`,
|
|
17
17
|
});
|
|
18
18
|
}
|
|
@@ -20,7 +20,7 @@ function validateTokenPayload(payload, rules = { requiredFields: ['exp', 'iat']
|
|
|
20
20
|
// 2. Forbidden fields
|
|
21
21
|
for (const field of forbiddenFields) {
|
|
22
22
|
if (field in payload) {
|
|
23
|
-
throw new
|
|
23
|
+
throw new errors_1.ValidationError({
|
|
24
24
|
reason: `Forbidden field in token: ${field}`,
|
|
25
25
|
});
|
|
26
26
|
}
|
|
@@ -29,7 +29,7 @@ function validateTokenPayload(payload, rules = { requiredFields: ['exp', 'iat']
|
|
|
29
29
|
for (const key in validateTypes) {
|
|
30
30
|
const expectedType = validateTypes[key];
|
|
31
31
|
if (key in payload && typeof payload[key] !== expectedType) {
|
|
32
|
-
throw new
|
|
32
|
+
throw new errors_1.ValidationError({
|
|
33
33
|
reason: `Invalid type for ${key}. Expected ${expectedType}, got ${typeof payload[key]}`,
|
|
34
34
|
});
|
|
35
35
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.safeVerifyTokenWithOptions = exports.safeVerifyToken = exports.verifyTokenWithOptions = exports.verifyToken = void 0;
|
|
4
|
-
const
|
|
4
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
5
5
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
6
6
|
/**
|
|
7
7
|
* Verify token (throws UnauthorizedError if invalid or expired)
|
|
@@ -12,12 +12,12 @@ const verifyToken = (token, secret) => {
|
|
|
12
12
|
}
|
|
13
13
|
catch (error) {
|
|
14
14
|
if (error.name === 'TokenExpiredError') {
|
|
15
|
-
throw new
|
|
15
|
+
throw new errors_1.UnauthorizedError({ reason: 'Token has expired' }, error);
|
|
16
16
|
}
|
|
17
17
|
if (error.name === 'JsonWebTokenError') {
|
|
18
|
-
throw new
|
|
18
|
+
throw new errors_1.UnauthorizedError({ reason: 'Invalid token' }, error);
|
|
19
19
|
}
|
|
20
|
-
throw new
|
|
20
|
+
throw new errors_1.UnauthorizedError({ reason: 'Failed to verify token' }, error);
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
exports.verifyToken = verifyToken;
|
|
@@ -30,12 +30,12 @@ const verifyTokenWithOptions = (token, secret, options = {}) => {
|
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
32
|
if (error.name === 'TokenExpiredError') {
|
|
33
|
-
throw new
|
|
33
|
+
throw new errors_1.UnauthorizedError({ reason: 'Token has expired' }, error);
|
|
34
34
|
}
|
|
35
35
|
if (error.name === 'JsonWebTokenError') {
|
|
36
|
-
throw new
|
|
36
|
+
throw new errors_1.UnauthorizedError({ reason: 'Invalid token' }, error);
|
|
37
37
|
}
|
|
38
|
-
throw new
|
|
38
|
+
throw new errors_1.UnauthorizedError({ reason: 'Failed to verify token' }, error);
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
exports.verifyTokenWithOptions = verifyTokenWithOptions;
|
|
@@ -50,13 +50,13 @@ const safeVerifyToken = (token, secret) => {
|
|
|
50
50
|
catch (error) {
|
|
51
51
|
let wrappedError;
|
|
52
52
|
if (error.name === 'TokenExpiredError') {
|
|
53
|
-
wrappedError = new
|
|
53
|
+
wrappedError = new errors_1.UnauthorizedError({ reason: 'Token has expired' }, error);
|
|
54
54
|
}
|
|
55
55
|
else if (error.name === 'JsonWebTokenError') {
|
|
56
|
-
wrappedError = new
|
|
56
|
+
wrappedError = new errors_1.UnauthorizedError({ reason: 'Invalid token' }, error);
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
|
-
wrappedError = new
|
|
59
|
+
wrappedError = new errors_1.UnauthorizedError({ reason: 'Failed to verify token' }, error);
|
|
60
60
|
}
|
|
61
61
|
return { valid: false, error: wrappedError };
|
|
62
62
|
}
|
|
@@ -73,15 +73,15 @@ const safeVerifyTokenWithOptions = (token, secret, options = {}) => {
|
|
|
73
73
|
catch (error) {
|
|
74
74
|
let wrappedError;
|
|
75
75
|
if (error.name === 'TokenExpiredError') {
|
|
76
|
-
wrappedError = new
|
|
76
|
+
wrappedError = new errors_1.UnauthorizedError({ reason: 'Token has expired' }, error instanceof Error ? error : undefined);
|
|
77
77
|
}
|
|
78
78
|
else if (error.name === 'JsonWebTokenError') {
|
|
79
|
-
wrappedError = new
|
|
79
|
+
wrappedError = new errors_1.UnauthorizedError({
|
|
80
80
|
reason: 'Invalid token',
|
|
81
81
|
}, error instanceof Error ? error : undefined);
|
|
82
82
|
}
|
|
83
83
|
else {
|
|
84
|
-
wrappedError = new
|
|
84
|
+
wrappedError = new errors_1.UnauthorizedError({ reason: 'Failed to verify token' }, error instanceof Error ? error : undefined);
|
|
85
85
|
}
|
|
86
86
|
return { valid: false, error: wrappedError };
|
|
87
87
|
}
|
|
@@ -6,7 +6,7 @@ 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
|
|
9
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
10
10
|
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
11
11
|
const utils_1 = require("./utils");
|
|
12
12
|
/**
|
|
@@ -19,7 +19,7 @@ const hashPassword = async (password, saltRounds = 10) => {
|
|
|
19
19
|
return bcryptjs_1.default.hash(password, salt);
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
|
-
throw new
|
|
22
|
+
throw new errors_1.InternalServerError({ reason: 'Password hashing failed' }, error instanceof Error ? error : undefined);
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
exports.hashPassword = hashPassword;
|
|
@@ -36,7 +36,7 @@ const hashPasswordSync = (password, saltRounds = 10) => {
|
|
|
36
36
|
return bcryptjs_1.default.hashSync(password, salt);
|
|
37
37
|
}
|
|
38
38
|
catch (error) {
|
|
39
|
-
throw new
|
|
39
|
+
throw new errors_1.InternalServerError({ reason: 'Password hashing failed' }, error instanceof Error ? error : undefined);
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
exports.hashPasswordSync = hashPasswordSync;
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PasswordManager = void 0;
|
|
7
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
8
8
|
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
9
|
-
const
|
|
9
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
class PasswordManager {
|
|
12
12
|
constructor(config = {}) {
|
|
@@ -37,11 +37,11 @@ class PasswordManager {
|
|
|
37
37
|
return { hash, salt: finalSalt };
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
|
-
if (error instanceof
|
|
41
|
-
error instanceof
|
|
40
|
+
if (error instanceof errors_1.BadRequestError ||
|
|
41
|
+
error instanceof errors_1.ValidationError) {
|
|
42
42
|
throw error;
|
|
43
43
|
}
|
|
44
|
-
throw new
|
|
44
|
+
throw new errors_1.BadRequestError({ reason: 'Failed to hash password' }, error instanceof Error ? error : undefined);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
@@ -64,7 +64,7 @@ class PasswordManager {
|
|
|
64
64
|
generate(length = 16, options = {}) {
|
|
65
65
|
const config = { ...this.defaultConfig, ...options };
|
|
66
66
|
if (length < config.minLength || length > config.maxLength) {
|
|
67
|
-
throw new
|
|
67
|
+
throw new errors_1.ValidationError({
|
|
68
68
|
reason: `Password length must be between ${config.minLength} and ${config.maxLength}`,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isPasswordStrong = void 0;
|
|
4
|
-
const
|
|
4
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
5
5
|
const isPasswordStrong = (password, options = {}) => {
|
|
6
6
|
if (!password)
|
|
7
|
-
throw new
|
|
7
|
+
throw new errors_1.BadRequestError({ reason: 'Invalid password provided' });
|
|
8
8
|
const { minLength = 8, requireUppercase = true, requireLowercase = true, requireNumbers = true, requireSymbols = false, } = options;
|
|
9
9
|
if (password.length < minLength)
|
|
10
|
-
throw new
|
|
10
|
+
throw new errors_1.ValidationError({
|
|
11
11
|
reason: `Password must be at least ${minLength} characters long`,
|
|
12
12
|
});
|
|
13
13
|
if (requireUppercase && !/[A-Z]/.test(password))
|
|
14
|
-
throw new
|
|
14
|
+
throw new errors_1.ValidationError({
|
|
15
15
|
reason: 'Password must include uppercase letters',
|
|
16
16
|
});
|
|
17
17
|
if (requireLowercase && !/[a-z]/.test(password))
|
|
18
|
-
throw new
|
|
18
|
+
throw new errors_1.ValidationError({
|
|
19
19
|
reason: 'Password must include lowercase letters',
|
|
20
20
|
});
|
|
21
21
|
if (requireNumbers && !/[0-9]/.test(password))
|
|
22
|
-
throw new
|
|
22
|
+
throw new errors_1.ValidationError({ reason: 'Password must include numbers' });
|
|
23
23
|
if (requireSymbols && !/[^A-Za-z0-9]/.test(password))
|
|
24
|
-
throw new
|
|
24
|
+
throw new errors_1.ValidationError({ reason: 'Password must include symbols' });
|
|
25
25
|
return true;
|
|
26
26
|
};
|
|
27
27
|
exports.isPasswordStrong = isPasswordStrong;
|
|
@@ -8,13 +8,13 @@ exports.safeCompare = safeCompare;
|
|
|
8
8
|
exports.estimatePasswordEntropy = estimatePasswordEntropy;
|
|
9
9
|
exports.normalizePassword = normalizePassword;
|
|
10
10
|
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
-
const
|
|
11
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
12
12
|
/**
|
|
13
13
|
* Ensure password is a valid non-empty string
|
|
14
14
|
*/
|
|
15
15
|
function ensureValidPassword(password) {
|
|
16
16
|
if (!password || typeof password !== 'string') {
|
|
17
|
-
throw new
|
|
17
|
+
throw new errors_1.BadRequestError({ reason: 'Invalid password provided' });
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -6,7 +6,7 @@ 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
|
|
9
|
+
const errors_1 = require("@naman_deep_singh/errors");
|
|
10
10
|
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
11
11
|
/**
|
|
12
12
|
* Compare a password with a stored hash asynchronously.
|
|
@@ -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
|
|
18
|
+
throw new errors_1.UnauthorizedError({ reason: 'Password verification failed' });
|
|
19
19
|
return result;
|
|
20
20
|
}
|
|
21
21
|
catch {
|
|
22
|
-
throw new
|
|
22
|
+
throw new errors_1.UnauthorizedError({ reason: '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
|
|
36
|
+
throw new errors_1.UnauthorizedError({ reason: 'Password verification failed' });
|
|
37
37
|
return result;
|
|
38
38
|
}
|
|
39
39
|
catch (_error) {
|
|
40
|
-
throw new
|
|
40
|
+
throw new errors_1.UnauthorizedError({ reason: 'Password verification failed' });
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
exports.verifyPasswordSync = verifyPasswordSync;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './core/password';
|
|
2
2
|
export * from './core/jwt';
|
|
3
3
|
export * from './core/crypto';
|
|
4
|
-
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors
|
|
4
|
+
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors';
|
|
5
5
|
import * as CryptoUtils from './core/crypto';
|
|
6
6
|
import * as JWTUtils from './core/jwt';
|
|
7
7
|
declare const _default: {
|
package/dist/cjs/index.js
CHANGED
|
@@ -41,11 +41,11 @@ __exportStar(require("./core/password"), exports);
|
|
|
41
41
|
__exportStar(require("./core/jwt"), exports);
|
|
42
42
|
__exportStar(require("./core/crypto"), exports);
|
|
43
43
|
// Re-export common errors for convenience
|
|
44
|
-
var
|
|
45
|
-
Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return
|
|
46
|
-
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return
|
|
47
|
-
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return
|
|
48
|
-
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return
|
|
44
|
+
var errors_1 = require("@naman_deep_singh/errors");
|
|
45
|
+
Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return errors_1.BadRequestError; } });
|
|
46
|
+
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return errors_1.UnauthorizedError; } });
|
|
47
|
+
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_1.ValidationError; } });
|
|
48
|
+
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return errors_1.InternalServerError; } });
|
|
49
49
|
const CryptoUtils = __importStar(require("./core/crypto"));
|
|
50
50
|
const JWTUtils = __importStar(require("./core/jwt"));
|
|
51
51
|
const PasswordUtils = __importStar(require("./core/password"));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CryptoIntegrityError } from '@naman_deep_singh/errors
|
|
1
|
+
import { CryptoIntegrityError } from '@naman_deep_singh/errors';
|
|
2
2
|
import { decrypt as functionalDecrypt, encrypt as functionalEncrypt, hmacSign as functionalHmacSign, hmacVerify as functionalHmacVerify, randomToken as functionalRandomToken, } from './index';
|
|
3
3
|
/**
|
|
4
4
|
* Default configuration
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import jwt from 'jsonwebtoken';
|
|
2
2
|
import { signToken } from './signToken';
|
|
3
3
|
import { safeVerifyToken } from './verify';
|
|
4
|
-
import { BadRequestError, UnauthorizedError, ValidationError, } from '@naman_deep_singh/errors
|
|
5
|
-
import { LRUCache } from '@naman_deep_singh/
|
|
4
|
+
import { BadRequestError, UnauthorizedError, ValidationError, } from '@naman_deep_singh/errors';
|
|
5
|
+
import { LRUCache } from '@naman_deep_singh/utils';
|
|
6
6
|
export class JWTManager {
|
|
7
7
|
constructor(config) {
|
|
8
8
|
this.accessSecret = config.accessSecret;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import bcrypt from 'bcryptjs';
|
|
3
|
-
import { BadRequestError, ValidationError
|
|
3
|
+
import { BadRequestError, ValidationError } from '@naman_deep_singh/errors';
|
|
4
4
|
import { ensureValidPassword, estimatePasswordEntropy } from './utils';
|
|
5
5
|
export class PasswordManager {
|
|
6
6
|
constructor(config = {}) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BadRequestError, ValidationError
|
|
1
|
+
import { BadRequestError, ValidationError } from '@naman_deep_singh/errors';
|
|
2
2
|
export const isPasswordStrong = (password, options = {}) => {
|
|
3
3
|
if (!password)
|
|
4
4
|
throw new BadRequestError({ reason: 'Invalid password provided' });
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './core/password';
|
|
2
2
|
export * from './core/jwt';
|
|
3
3
|
export * from './core/crypto';
|
|
4
|
-
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors
|
|
4
|
+
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors';
|
|
5
5
|
import * as CryptoUtils from './core/crypto';
|
|
6
6
|
import * as JWTUtils from './core/jwt';
|
|
7
7
|
declare const _default: {
|
package/dist/esm/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export * from './core/password';
|
|
|
2
2
|
export * from './core/jwt';
|
|
3
3
|
export * from './core/crypto';
|
|
4
4
|
// Re-export common errors for convenience
|
|
5
|
-
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors
|
|
5
|
+
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors';
|
|
6
6
|
import * as CryptoUtils from './core/crypto';
|
|
7
7
|
import * as JWTUtils from './core/jwt';
|
|
8
8
|
import * as PasswordUtils from './core/password';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './core/password';
|
|
2
2
|
export * from './core/jwt';
|
|
3
3
|
export * from './core/crypto';
|
|
4
|
-
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors
|
|
4
|
+
export { BadRequestError, UnauthorizedError, ValidationError, InternalServerError, } from '@naman_deep_singh/errors';
|
|
5
5
|
import * as CryptoUtils from './core/crypto';
|
|
6
6
|
import * as JWTUtils from './core/jwt';
|
|
7
7
|
declare const _default: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naman_deep_singh/security",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Security utilities for password hashing and JWT token management with TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"author": "Naman Deep Singh",
|
|
29
29
|
"license": "ISC",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@naman_deep_singh/errors
|
|
32
|
-
"@naman_deep_singh/
|
|
31
|
+
"@naman_deep_singh/errors": "^2.1.0",
|
|
32
|
+
"@naman_deep_singh/utils": "^2.1.1",
|
|
33
33
|
"bcryptjs": "^3.0.3",
|
|
34
34
|
"jsonwebtoken": "^9.0.2"
|
|
35
35
|
},
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"rimraf": "^5.0.5",
|
|
40
40
|
"typescript": "^5.9.3"
|
|
41
41
|
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
42
45
|
"scripts": {
|
|
43
46
|
"build": "pnpm run build:types && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json",
|
|
44
47
|
"build:types": "tsc -p tsconfig.base.json --emitDeclarationOnly --outDir dist/types",
|