@nivinjoseph/n-sec 6.0.3 → 7.0.1
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/.yarn/releases/yarn-4.14.1.cjs +940 -0
- package/.yarnrc.yml +6 -1
- package/dist/api-security/claim.js +2 -0
- package/dist/api-security/claim.js.map +1 -1
- package/dist/api-security/claims-identity.js +1 -0
- package/dist/api-security/claims-identity.js.map +1 -1
- package/dist/api-security/expired-token-exception.js +1 -0
- package/dist/api-security/expired-token-exception.js.map +1 -1
- package/dist/api-security/invalid-token-exception.js +2 -0
- package/dist/api-security/invalid-token-exception.js.map +1 -1
- package/dist/api-security/json-web-token.d.ts +1 -1
- package/dist/api-security/json-web-token.d.ts.map +1 -1
- package/dist/api-security/json-web-token.js +35 -10
- package/dist/api-security/json-web-token.js.map +1 -1
- package/dist/api-security/security-token.js +2 -0
- package/dist/api-security/security-token.js.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/crypto/hash.d.ts +40 -0
- package/dist/crypto/hash.d.ts.map +1 -1
- package/dist/crypto/hash.js +60 -1
- package/dist/crypto/hash.js.map +1 -1
- package/dist/crypto/symmetric-encryption.d.ts +51 -3
- package/dist/crypto/symmetric-encryption.d.ts.map +1 -1
- package/dist/crypto/symmetric-encryption.js +90 -44
- package/dist/crypto/symmetric-encryption.js.map +1 -1
- package/dist/tsconfig.json +1 -0
- package/eslint.config.js +5 -5
- package/package.json +15 -15
- package/src/api-security/json-web-token.ts +37 -12
- package/src/bin.ts +1 -1
- package/src/crypto/hash.ts +66 -1
- package/src/crypto/symmetric-encryption.ts +98 -55
- package/test/hash.test.ts +89 -0
- package/test/hmac.test.ts +12 -12
- package/test/json-web-token.test.ts +76 -10
- package/test/symmetric-encryption.test.ts +51 -12
- package/tsconfig.json +5 -2
- package/.yarn/releases/yarn-4.0.2.cjs +0 -893
|
@@ -2,20 +2,29 @@ import { describe, test } from "node:test";
|
|
|
2
2
|
import assert from "node:assert";
|
|
3
3
|
import { JsonWebToken } from "./../src/api-security/json-web-token.js";
|
|
4
4
|
import { Claim } from "../src/api-security/claim.js";
|
|
5
|
-
import { SymmetricEncryption } from "../src/index.js";
|
|
5
|
+
import { Hmac, SymmetricEncryption } from "../src/index.js";
|
|
6
6
|
import { InvalidTokenException } from "../src/api-security/invalid-token-exception.js";
|
|
7
7
|
import { ExpiredTokenException } from "../src/api-security/expired-token-exception.js";
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
function buildToken(key: string, headerJson: string, bodyJson: string): string
|
|
11
|
+
{
|
|
12
|
+
const headerHex = Buffer.from(headerJson, "utf8").toString("hex").toUpperCase();
|
|
13
|
+
const bodyHex = Buffer.from(bodyJson, "utf8").toString("hex").toUpperCase();
|
|
14
|
+
const signature = Hmac.create(key, `${headerHex}.${bodyHex}`);
|
|
15
|
+
return `${headerHex}.${bodyHex}.${signature}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
10
19
|
await describe("Json Web Token ", async () =>
|
|
11
20
|
{
|
|
12
21
|
await describe("Hmac", async () =>
|
|
13
22
|
{
|
|
14
23
|
|
|
15
|
-
await test("should successfully create a token using hmac with one claim",
|
|
24
|
+
await test("should successfully create a token using hmac with one claim", () =>
|
|
16
25
|
{
|
|
17
26
|
const claim = new Claim("this_claim", "ThisValue");
|
|
18
|
-
const key =
|
|
27
|
+
const key = SymmetricEncryption.generateKey();
|
|
19
28
|
const time = Date.now();
|
|
20
29
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time + 10000000, [claim]).generateToken();
|
|
21
30
|
const jwt = JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
@@ -31,7 +40,7 @@ await describe("Json Web Token ", async () =>
|
|
|
31
40
|
{
|
|
32
41
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
33
42
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
34
|
-
const key =
|
|
43
|
+
const key = SymmetricEncryption.generateKey();
|
|
35
44
|
const time = Date.now();
|
|
36
45
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time + 10000000, [claim1, claim2]).generateToken();
|
|
37
46
|
const jwt = JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
@@ -47,7 +56,7 @@ await describe("Json Web Token ", async () =>
|
|
|
47
56
|
{
|
|
48
57
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
49
58
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
50
|
-
const key =
|
|
59
|
+
const key = SymmetricEncryption.generateKey();
|
|
51
60
|
const time = Date.now();
|
|
52
61
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time + 10000000, [claim1, claim2]).generateToken();
|
|
53
62
|
const jwt = JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
@@ -63,7 +72,7 @@ await describe("Json Web Token ", async () =>
|
|
|
63
72
|
{
|
|
64
73
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
65
74
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
66
|
-
const key =
|
|
75
|
+
const key = SymmetricEncryption.generateKey();
|
|
67
76
|
const time = Date.now();
|
|
68
77
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time + 10000000, [claim1, claim2]).generateToken();
|
|
69
78
|
try
|
|
@@ -83,7 +92,7 @@ await describe("Json Web Token ", async () =>
|
|
|
83
92
|
{
|
|
84
93
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
85
94
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
86
|
-
const key =
|
|
95
|
+
const key = SymmetricEncryption.generateKey();
|
|
87
96
|
const time = Date.now();
|
|
88
97
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time, [claim1, claim2]).generateToken();
|
|
89
98
|
try
|
|
@@ -125,8 +134,8 @@ await describe("Json Web Token ", async () =>
|
|
|
125
134
|
{
|
|
126
135
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
127
136
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
128
|
-
const key =
|
|
129
|
-
const key2 =
|
|
137
|
+
const key = SymmetricEncryption.generateKey();
|
|
138
|
+
const key2 = SymmetricEncryption.generateKey();
|
|
130
139
|
const time = Date.now();
|
|
131
140
|
const token = JsonWebToken.fromClaims("issuer1", 1, key, time + 1000000, [claim1, claim2]).generateToken();
|
|
132
141
|
try
|
|
@@ -146,7 +155,7 @@ await describe("Json Web Token ", async () =>
|
|
|
146
155
|
{
|
|
147
156
|
const claim1 = new Claim("this_claim", "ThisValue");
|
|
148
157
|
const claim2 = new Claim("that_claim", "ThatValue");
|
|
149
|
-
const key =
|
|
158
|
+
const key = SymmetricEncryption.generateKey();
|
|
150
159
|
const time = Date.now();
|
|
151
160
|
let token = JsonWebToken.fromClaims("issuer1", 1, key, time + 1000000, [claim1, claim2]).generateToken();
|
|
152
161
|
token = token + "someStuff";
|
|
@@ -162,6 +171,63 @@ await describe("Json Web Token ", async () =>
|
|
|
162
171
|
}
|
|
163
172
|
assert.ok(false);
|
|
164
173
|
});
|
|
174
|
+
|
|
175
|
+
await test("should throw an exception when body contains '__proto__' as a claim type", () =>
|
|
176
|
+
{
|
|
177
|
+
const key = SymmetricEncryption.generateKey();
|
|
178
|
+
const headerJson = JSON.stringify({ iss: "issuer1", alg: 1, exp: Date.now() + 10000000 });
|
|
179
|
+
const bodyJson = `{"__proto__":"evil"}`;
|
|
180
|
+
const token = buildToken(key, headerJson, bodyJson);
|
|
181
|
+
try
|
|
182
|
+
{
|
|
183
|
+
JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
184
|
+
}
|
|
185
|
+
catch (exp)
|
|
186
|
+
{
|
|
187
|
+
assert.ok(exp instanceof InvalidTokenException);
|
|
188
|
+
assert.equal(exp.message, `Token '${token}' is invalid because body contains invalid key '__proto__'.`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
assert.ok(false);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
await test("should throw an exception when body contains 'constructor' as a claim type", () =>
|
|
195
|
+
{
|
|
196
|
+
const key = SymmetricEncryption.generateKey();
|
|
197
|
+
const headerJson = JSON.stringify({ iss: "issuer1", alg: 1, exp: Date.now() + 10000000 });
|
|
198
|
+
const bodyJson = `{"constructor":"evil"}`;
|
|
199
|
+
const token = buildToken(key, headerJson, bodyJson);
|
|
200
|
+
try
|
|
201
|
+
{
|
|
202
|
+
JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
203
|
+
}
|
|
204
|
+
catch (exp)
|
|
205
|
+
{
|
|
206
|
+
assert.ok(exp instanceof InvalidTokenException);
|
|
207
|
+
assert.equal(exp.message, `Token '${token}' is invalid because body contains invalid key 'constructor'.`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
assert.ok(false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await test("should throw an exception when body contains 'prototype' as a claim type", () =>
|
|
214
|
+
{
|
|
215
|
+
const key = SymmetricEncryption.generateKey();
|
|
216
|
+
const headerJson = JSON.stringify({ iss: "issuer1", alg: 1, exp: Date.now() + 10000000 });
|
|
217
|
+
const bodyJson = `{"prototype":"evil"}`;
|
|
218
|
+
const token = buildToken(key, headerJson, bodyJson);
|
|
219
|
+
try
|
|
220
|
+
{
|
|
221
|
+
JsonWebToken.fromToken("issuer1", 1, key, token);
|
|
222
|
+
}
|
|
223
|
+
catch (exp)
|
|
224
|
+
{
|
|
225
|
+
assert.ok(exp instanceof InvalidTokenException);
|
|
226
|
+
assert.equal(exp.message, `Token '${token}' is invalid because body contains invalid key 'prototype'.`);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
assert.ok(false);
|
|
230
|
+
});
|
|
165
231
|
});
|
|
166
232
|
|
|
167
233
|
// await describe("digital Signature", () =>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
-
import { SymmetricEncryption } from "./../src/index.js";
|
|
4
|
-
// import { CryptoException } from "./../src/crypto-exception";
|
|
3
|
+
import { CryptoException, SymmetricEncryption } from "./../src/index.js";
|
|
5
4
|
import "@nivinjoseph/n-ext";
|
|
6
5
|
|
|
7
6
|
|
|
@@ -9,30 +8,30 @@ await describe("SymmetricEncryption", async () =>
|
|
|
9
8
|
{
|
|
10
9
|
await describe("generateKey", async () =>
|
|
11
10
|
{
|
|
12
|
-
await test("must return string value that is not null, empty or whitespace",
|
|
11
|
+
await test("must return string value that is not null, empty or whitespace", () =>
|
|
13
12
|
{
|
|
14
|
-
const key =
|
|
13
|
+
const key = SymmetricEncryption.generateKey();
|
|
15
14
|
console.log("key", key);
|
|
16
15
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
17
16
|
assert.ok(key !== null && !key.isEmptyOrWhiteSpace());
|
|
18
17
|
});
|
|
19
18
|
|
|
20
19
|
|
|
21
|
-
await test("consecutive calls must yield unique values",
|
|
20
|
+
await test("consecutive calls must yield unique values", () =>
|
|
22
21
|
{
|
|
23
|
-
const key1 =
|
|
24
|
-
const key2 =
|
|
22
|
+
const key1 = SymmetricEncryption.generateKey();
|
|
23
|
+
const key2 = SymmetricEncryption.generateKey();
|
|
25
24
|
assert.notStrictEqual(key1, key2);
|
|
26
25
|
});
|
|
27
26
|
});
|
|
28
27
|
|
|
29
28
|
await describe("encrypt", async () =>
|
|
30
29
|
{
|
|
31
|
-
await test("must return cipher text value when called with key and plain text value",
|
|
30
|
+
await test("must return cipher text value when called with key and plain text value", () =>
|
|
32
31
|
{
|
|
33
32
|
const key = "E25B269440F88601C453CD171D76EDDC11D8CF33230742DF8CAD5873D28F78B2";
|
|
34
33
|
const value = "password";
|
|
35
|
-
const encrypted =
|
|
34
|
+
const encrypted = SymmetricEncryption.encrypt(key, value);
|
|
36
35
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
37
36
|
assert.ok(encrypted !== null);
|
|
38
37
|
assert.notStrictEqual(encrypted, value);
|
|
@@ -172,15 +171,55 @@ await describe("SymmetricEncryption", async () =>
|
|
|
172
171
|
|
|
173
172
|
await describe("decrypt", async () =>
|
|
174
173
|
{
|
|
175
|
-
await test("must return plain text value when called with key and cipher text value",
|
|
174
|
+
await test("must return plain text value when called with key and cipher text value", () =>
|
|
176
175
|
{
|
|
177
|
-
const key =
|
|
176
|
+
const key = SymmetricEncryption.generateKey();
|
|
178
177
|
const value = "password";
|
|
179
|
-
const encrypted =
|
|
178
|
+
const encrypted = SymmetricEncryption.encrypt(key, value);
|
|
180
179
|
const decrypted = SymmetricEncryption.decrypt(key, encrypted);
|
|
181
180
|
assert.strictEqual(decrypted, value);
|
|
182
181
|
});
|
|
183
182
|
|
|
183
|
+
await test("round-trips successfully when the same aad is supplied to encrypt and decrypt", () =>
|
|
184
|
+
{
|
|
185
|
+
const key = SymmetricEncryption.generateKey();
|
|
186
|
+
const value = "password";
|
|
187
|
+
const aad = "user:42|purpose:session";
|
|
188
|
+
const encrypted = SymmetricEncryption.encrypt(key, value, aad);
|
|
189
|
+
const decrypted = SymmetricEncryption.decrypt(key, encrypted, aad);
|
|
190
|
+
assert.strictEqual(decrypted, value);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await test("throws CryptoException when decrypting with a different aad than was used to encrypt", () =>
|
|
194
|
+
{
|
|
195
|
+
const key = SymmetricEncryption.generateKey();
|
|
196
|
+
const encrypted = SymmetricEncryption.encrypt(key, "password", "user:42");
|
|
197
|
+
assert.throws(
|
|
198
|
+
() => SymmetricEncryption.decrypt(key, encrypted, "user:99"),
|
|
199
|
+
CryptoException
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
await test("throws CryptoException when decrypting without aad a ciphertext that was encrypted with aad", () =>
|
|
204
|
+
{
|
|
205
|
+
const key = SymmetricEncryption.generateKey();
|
|
206
|
+
const encrypted = SymmetricEncryption.encrypt(key, "password", "user:42");
|
|
207
|
+
assert.throws(
|
|
208
|
+
() => SymmetricEncryption.decrypt(key, encrypted),
|
|
209
|
+
CryptoException
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await test("throws CryptoException when decrypting with aad a ciphertext that was encrypted without aad", () =>
|
|
214
|
+
{
|
|
215
|
+
const key = SymmetricEncryption.generateKey();
|
|
216
|
+
const encrypted = SymmetricEncryption.encrypt(key, "password");
|
|
217
|
+
assert.throws(
|
|
218
|
+
() => SymmetricEncryption.decrypt(key, encrypted, "user:42"),
|
|
219
|
+
CryptoException
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
184
223
|
// await test("decrypt with a valid encryption key", async () =>
|
|
185
224
|
// {
|
|
186
225
|
// let key = await SymmetricEncryption.generateKey();
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"module": "NodeNext",
|
|
4
|
-
"target": "
|
|
4
|
+
"target": "ES2023",
|
|
5
5
|
"lib": [
|
|
6
6
|
"ES2023"
|
|
7
7
|
],
|
|
8
|
+
"types": [
|
|
9
|
+
"node"
|
|
10
|
+
],
|
|
8
11
|
"strict": true,
|
|
9
12
|
"strictNullChecks": true,
|
|
10
13
|
"strictFunctionTypes": true,
|
|
@@ -23,7 +26,7 @@
|
|
|
23
26
|
"noEmitHelpers": true,
|
|
24
27
|
"noImplicitOverride": true,
|
|
25
28
|
"pretty": true,
|
|
26
|
-
"esModuleInterop":
|
|
29
|
+
"esModuleInterop": true,
|
|
27
30
|
"allowSyntheticDefaultImports": true
|
|
28
31
|
}
|
|
29
32
|
}
|