zerohelper-security 11.0.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 +70 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/package.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# zerohelper-security
|
|
2
|
+
|
|
3
|
+
Security utilities for ZeroHelper.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install zerohelper-security
|
|
9
|
+
npm install bcrypt jsonwebtoken
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import {
|
|
16
|
+
hashPassword, verifyPassword,
|
|
17
|
+
generateJWT, verifyJWT,
|
|
18
|
+
encryptText, decryptText,
|
|
19
|
+
validateUUID, isPasswordStrong,
|
|
20
|
+
checkRateLimit
|
|
21
|
+
} from 'zerohelper-security';
|
|
22
|
+
|
|
23
|
+
// Password hashing
|
|
24
|
+
const hash = hashPassword('myPassword');
|
|
25
|
+
const valid = verifyPassword('myPassword', hash);
|
|
26
|
+
|
|
27
|
+
// JWT tokens
|
|
28
|
+
const token = generateJWT({ userId: 123 }, 'secret', '1h');
|
|
29
|
+
const payload = verifyJWT(token, 'secret');
|
|
30
|
+
|
|
31
|
+
// Encryption
|
|
32
|
+
const { encryptedText, iv } = encryptText('secret', 'myKey');
|
|
33
|
+
const decrypted = decryptText(encryptedText, 'myKey', iv);
|
|
34
|
+
|
|
35
|
+
// Validation
|
|
36
|
+
const isValid = validateUUID('550e8400-e29b-41d4-a716-446655440000');
|
|
37
|
+
const isStrong = isPasswordStrong('Test@123');
|
|
38
|
+
|
|
39
|
+
// Rate limiting
|
|
40
|
+
const result = await checkRateLimit('user:123', {
|
|
41
|
+
limit: 10,
|
|
42
|
+
window: 60000,
|
|
43
|
+
storage: 'memory'
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Functions
|
|
48
|
+
|
|
49
|
+
### Password
|
|
50
|
+
- `hashPassword(password)` - Hash with bcrypt
|
|
51
|
+
- `verifyPassword(password, hash)` - Verify bcrypt hash
|
|
52
|
+
|
|
53
|
+
### JWT
|
|
54
|
+
- `generateJWT(payload, secret, expiresIn)` - Generate JWT
|
|
55
|
+
- `verifyJWT(token, secret)` - Verify JWT
|
|
56
|
+
|
|
57
|
+
### Encryption
|
|
58
|
+
- `encryptText(text, secret)` - AES-256 encryption
|
|
59
|
+
- `decryptText(encryptedText, secret, iv)` - AES-256 decryption
|
|
60
|
+
|
|
61
|
+
### Validation
|
|
62
|
+
- `validateUUID(uuid)` - Validate UUID v1-5
|
|
63
|
+
- `isPasswordStrong(password)` - Check password strength
|
|
64
|
+
|
|
65
|
+
### Rate Limiting
|
|
66
|
+
- `checkRateLimit(key, options)` - Rate limit check
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
ISC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare function hashPassword(password: string): string;
|
|
2
|
+
export declare function verifyPassword(password: string, hash: string): boolean;
|
|
3
|
+
export declare function generateJWT(payload: object, secret: string, expiresIn?: string): string;
|
|
4
|
+
export declare function verifyJWT(token: string, secret: string): any;
|
|
5
|
+
export declare function generateSalt(): string;
|
|
6
|
+
export declare function encryptText(text: string, secret: string): {
|
|
7
|
+
encryptedText: string;
|
|
8
|
+
iv: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function decryptText(encryptedText: string, secret: string, ivHex: string): string;
|
|
11
|
+
export declare function validateUUID(uuid: string): boolean;
|
|
12
|
+
export declare function isPasswordStrong(password: string): boolean;
|
|
13
|
+
interface RateLimitResult {
|
|
14
|
+
allowed: boolean;
|
|
15
|
+
remaining: number;
|
|
16
|
+
resetAt: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function checkRateLimit(key: string, opts: {
|
|
19
|
+
limit: number;
|
|
20
|
+
window: number;
|
|
21
|
+
storage: 'memory' | 'redis';
|
|
22
|
+
redisClient?: any;
|
|
23
|
+
}): Promise<RateLimitResult>;
|
|
24
|
+
export declare const crypto_module: {
|
|
25
|
+
encryptText: typeof encryptText;
|
|
26
|
+
decryptText: typeof decryptText;
|
|
27
|
+
hashPassword: typeof hashPassword;
|
|
28
|
+
verifyPassword: typeof verifyPassword;
|
|
29
|
+
generateJWT: typeof generateJWT;
|
|
30
|
+
verifyJWT: typeof verifyJWT;
|
|
31
|
+
generateSalt: typeof generateSalt;
|
|
32
|
+
validateUUID: typeof validateUUID;
|
|
33
|
+
isPasswordStrong: typeof isPasswordStrong;
|
|
34
|
+
};
|
|
35
|
+
export declare const security_module: {
|
|
36
|
+
checkRateLimit: typeof checkRateLimit;
|
|
37
|
+
};
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,MAAM,CAE7F;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAM5D;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAO/F;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOxF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,GAAG,CAAA;CAAE,GACtF,OAAO,CAAC,eAAe,CAAC,CA0B1B;AAED,eAAO,MAAM,aAAa;;;;;;;;;;CAUzB,CAAC;AAEF,eAAO,MAAM,eAAe;;CAE3B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.security_module = exports.crypto_module = void 0;
|
|
7
|
+
exports.hashPassword = hashPassword;
|
|
8
|
+
exports.verifyPassword = verifyPassword;
|
|
9
|
+
exports.generateJWT = generateJWT;
|
|
10
|
+
exports.verifyJWT = verifyJWT;
|
|
11
|
+
exports.generateSalt = generateSalt;
|
|
12
|
+
exports.encryptText = encryptText;
|
|
13
|
+
exports.decryptText = decryptText;
|
|
14
|
+
exports.validateUUID = validateUUID;
|
|
15
|
+
exports.isPasswordStrong = isPasswordStrong;
|
|
16
|
+
exports.checkRateLimit = checkRateLimit;
|
|
17
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
18
|
+
const bcrypt_1 = __importDefault(require("bcrypt"));
|
|
19
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
20
|
+
function hashPassword(password) {
|
|
21
|
+
return bcrypt_1.default.hashSync(password, 10);
|
|
22
|
+
}
|
|
23
|
+
function verifyPassword(password, hash) {
|
|
24
|
+
return bcrypt_1.default.compareSync(password, hash);
|
|
25
|
+
}
|
|
26
|
+
function generateJWT(payload, secret, expiresIn = "1h") {
|
|
27
|
+
return jsonwebtoken_1.default.sign(payload, secret, { expiresIn: expiresIn });
|
|
28
|
+
}
|
|
29
|
+
function verifyJWT(token, secret) {
|
|
30
|
+
try {
|
|
31
|
+
return jsonwebtoken_1.default.verify(token, secret);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function generateSalt() {
|
|
38
|
+
return crypto_1.default.randomBytes(16).toString("hex");
|
|
39
|
+
}
|
|
40
|
+
function encryptText(text, secret) {
|
|
41
|
+
const key = crypto_1.default.pbkdf2Sync(secret, generateSalt(), 100000, 32, 'sha512');
|
|
42
|
+
const iv = crypto_1.default.randomBytes(16);
|
|
43
|
+
const cipher = crypto_1.default.createCipheriv("aes-256-cbc", key, iv);
|
|
44
|
+
let encrypted = cipher.update(text, "utf8", "hex");
|
|
45
|
+
encrypted += cipher.final("hex");
|
|
46
|
+
return { encryptedText: encrypted, iv: iv.toString('hex') };
|
|
47
|
+
}
|
|
48
|
+
function decryptText(encryptedText, secret, ivHex) {
|
|
49
|
+
const key = crypto_1.default.pbkdf2Sync(secret, generateSalt(), 100000, 32, 'sha512');
|
|
50
|
+
const iv = Buffer.from(ivHex, 'hex');
|
|
51
|
+
const decipher = crypto_1.default.createDecipheriv("aes-256-cbc", key, iv);
|
|
52
|
+
let decrypted = decipher.update(encryptedText, "hex", "utf8");
|
|
53
|
+
decrypted += decipher.final("utf8");
|
|
54
|
+
return decrypted;
|
|
55
|
+
}
|
|
56
|
+
function validateUUID(uuid) {
|
|
57
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
58
|
+
return uuidRegex.test(uuid);
|
|
59
|
+
}
|
|
60
|
+
function isPasswordStrong(password) {
|
|
61
|
+
const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
|
|
62
|
+
return strongPasswordRegex.test(password);
|
|
63
|
+
}
|
|
64
|
+
const memoryStore = new Map();
|
|
65
|
+
async function checkRateLimit(key, opts) {
|
|
66
|
+
const limit = opts.limit;
|
|
67
|
+
const windowMs = opts.window;
|
|
68
|
+
const storage = opts.storage;
|
|
69
|
+
const redisClient = opts.redisClient;
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const resetAt = now + windowMs;
|
|
72
|
+
if (storage === 'redis' && redisClient) {
|
|
73
|
+
try {
|
|
74
|
+
const current = await redisClient.incr(`ratelimit:${key}`);
|
|
75
|
+
if (current === 1) {
|
|
76
|
+
await redisClient.expire(`ratelimit:${key}`, Math.ceil(windowMs / 1000));
|
|
77
|
+
}
|
|
78
|
+
return { allowed: current <= limit, remaining: Math.max(0, limit - current), resetAt };
|
|
79
|
+
}
|
|
80
|
+
catch { }
|
|
81
|
+
}
|
|
82
|
+
const current = memoryStore.get(key) || { count: 0, resetAt: 0 };
|
|
83
|
+
if (now > current.resetAt) {
|
|
84
|
+
current.count = 0;
|
|
85
|
+
current.resetAt = resetAt;
|
|
86
|
+
}
|
|
87
|
+
current.count++;
|
|
88
|
+
memoryStore.set(key, current);
|
|
89
|
+
return { allowed: current.count <= limit, remaining: Math.max(0, limit - current.count), resetAt };
|
|
90
|
+
}
|
|
91
|
+
exports.crypto_module = {
|
|
92
|
+
encryptText,
|
|
93
|
+
decryptText,
|
|
94
|
+
hashPassword,
|
|
95
|
+
verifyPassword,
|
|
96
|
+
generateJWT,
|
|
97
|
+
verifyJWT,
|
|
98
|
+
generateSalt,
|
|
99
|
+
validateUUID,
|
|
100
|
+
isPasswordStrong,
|
|
101
|
+
};
|
|
102
|
+
exports.security_module = {
|
|
103
|
+
checkRateLimit,
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zerohelper-security",
|
|
3
|
+
"version": "11.0.0",
|
|
4
|
+
"description": "Security utilities for ZeroHelper",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": { "build": "tsc", "clean": "rm -rf dist" },
|
|
8
|
+
"keywords": ["zerohelper", "security", "crypto", "bcrypt", "jwt"],
|
|
9
|
+
"author": "Onure9e",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": { "bcrypt": "^5.1.1", "jsonwebtoken": "^9.0.2" },
|
|
12
|
+
"devDependencies": { "@types/bcrypt": "^5.0.2", "@types/jsonwebtoken": "^9.0.7", "@types/node": "^22.10.2", "typescript": "^5.7.2" },
|
|
13
|
+
"files": ["dist", "README.md"],
|
|
14
|
+
"publishConfig": { "access": "public" }
|
|
15
|
+
}
|