cipher-kit 2.0.0 → 2.1.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 +25 -27
- package/dist/{chunk-3UX5MZ2P.cjs → chunk-BHG5RSUV.cjs} +22 -20
- package/dist/chunk-BHG5RSUV.cjs.map +1 -0
- package/dist/{chunk-4MFF6V3R.js → chunk-CRTOKS3Q.js} +76 -41
- package/dist/chunk-CRTOKS3Q.js.map +1 -0
- package/dist/{chunk-N2EW2FDZ.cjs → chunk-HMTHK2IY.cjs} +183 -148
- package/dist/chunk-HMTHK2IY.cjs.map +1 -0
- package/dist/{chunk-ACFPMIXO.js → chunk-RAEBT46G.js} +75 -40
- package/dist/chunk-RAEBT46G.js.map +1 -0
- package/dist/{chunk-FKSYSPJR.js → chunk-RUTGDMVR.js} +21 -20
- package/dist/chunk-RUTGDMVR.js.map +1 -0
- package/dist/{chunk-CVCDAHDW.cjs → chunk-UVEMRK5F.cjs} +189 -154
- package/dist/chunk-UVEMRK5F.cjs.map +1 -0
- package/dist/{export-BMvZq46v.d.ts → export-5hmOiU0J.d.cts} +194 -20
- package/dist/{export-CQNsJFh_.d.cts → export-BF9wW56f.d.ts} +194 -20
- package/dist/{export-llM6c7Do.d.ts → export-DVERZibl.d.cts} +194 -20
- package/dist/{export-55tHE0Bw.d.cts → export-w8sBcKXw.d.ts} +194 -20
- package/dist/index.cjs +12 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +33 -33
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/{validate-EHuJC5QQ.d.cts → validate-B3uHoP8n.d.cts} +26 -38
- package/dist/{validate-EHuJC5QQ.d.ts → validate-B3uHoP8n.d.ts} +26 -38
- package/dist/web-api.cjs +33 -33
- package/dist/web-api.d.cts +2 -2
- package/dist/web-api.d.ts +2 -2
- package/dist/web-api.js +2 -2
- package/package.json +6 -7
- package/dist/chunk-3UX5MZ2P.cjs.map +0 -1
- package/dist/chunk-4MFF6V3R.js.map +0 -1
- package/dist/chunk-ACFPMIXO.js.map +0 -1
- package/dist/chunk-CVCDAHDW.cjs.map +0 -1
- package/dist/chunk-FKSYSPJR.js.map +0 -1
- package/dist/chunk-N2EW2FDZ.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -41,20 +41,20 @@ bun add cipher-kit@latest
|
|
|
41
41
|
## Quick Start 🚀
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
|
-
// Node.js
|
|
44
|
+
// Node.js
|
|
45
45
|
import { createSecretKey, encrypt, decrypt } from "cipher-kit/node";
|
|
46
46
|
|
|
47
|
-
const
|
|
48
|
-
const encrypted = encrypt("Hello World!",
|
|
49
|
-
const decrypted = decrypt(encrypted,
|
|
47
|
+
const secretKey = createSecretKey("my-passphrase");
|
|
48
|
+
const encrypted = encrypt("Hello World!", secretKey);
|
|
49
|
+
const decrypted = decrypt(encrypted, secretKey);
|
|
50
50
|
console.log(decrypted); // "Hello World!"
|
|
51
51
|
|
|
52
|
-
// Web
|
|
52
|
+
// Web - including Deno, Bun, Cloudflare Workers
|
|
53
53
|
import { createSecretKey, encrypt, decrypt } from "cipher-kit/web-api";
|
|
54
54
|
|
|
55
|
-
const
|
|
56
|
-
const encrypted = await encrypt("Hello World!",
|
|
57
|
-
const decrypted = await decrypt(encrypted,
|
|
55
|
+
const secretKey = await createSecretKey("my-passphrase");
|
|
56
|
+
const encrypted = await encrypt("Hello World!", secretKey);
|
|
57
|
+
const decrypted = await decrypt(encrypted, secretKey);
|
|
58
58
|
console.log(decrypted); // "Hello World!"
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -129,6 +129,7 @@ Encryption is the process of converting readable plaintext into unreadable ciphe
|
|
|
129
129
|
#### _Secret Key Creation_ 🔑
|
|
130
130
|
|
|
131
131
|
Before encrypting or decrypting data, you need to create a secret key.
|
|
132
|
+
The key must be at least 8 characters long.
|
|
132
133
|
|
|
133
134
|
Each key is tied to a specific platform (Web or Node.js) and cannot be used interchangeably.
|
|
134
135
|
|
|
@@ -188,7 +189,7 @@ The function accepts an optional `options` parameter to customize the output enc
|
|
|
188
189
|
```typescript
|
|
189
190
|
interface EncryptOptions {
|
|
190
191
|
// Output ciphertext encoding(default: "base64url")
|
|
191
|
-
|
|
192
|
+
outputEncoding?: "base64url" | "base64" | "hex";
|
|
192
193
|
}
|
|
193
194
|
```
|
|
194
195
|
|
|
@@ -217,7 +218,7 @@ Make sure to use the same encoding that was used during encryption.
|
|
|
217
218
|
```typescript
|
|
218
219
|
interface DecryptOptions {
|
|
219
220
|
// Input ciphertext encoding (default: "base64url")
|
|
220
|
-
|
|
221
|
+
inputEncoding?: "base64url" | "base64" | "hex";
|
|
221
222
|
}
|
|
222
223
|
```
|
|
223
224
|
|
|
@@ -275,7 +276,7 @@ interface HashOptions {
|
|
|
275
276
|
digest?: "sha256" | "sha384" | "sha512";
|
|
276
277
|
|
|
277
278
|
// Output encoding (default: "base64url").
|
|
278
|
-
|
|
279
|
+
outputEncoding?: "base64url" | "base64" | "hex";
|
|
279
280
|
}
|
|
280
281
|
```
|
|
281
282
|
|
|
@@ -309,19 +310,19 @@ To verify a password, the same hashing process is applied to the input password,
|
|
|
309
310
|
// Node.js example
|
|
310
311
|
import { hashPassword, verifyPassword } from "cipher-kit/node";
|
|
311
312
|
|
|
312
|
-
const {
|
|
313
|
-
console.log(`Hashed Password: ${
|
|
313
|
+
const { result, salt } = hashPassword("some-secure-password");
|
|
314
|
+
console.log(`Hashed Password: ${result}`);
|
|
314
315
|
|
|
315
|
-
const isMatch = verifyPassword("some-secure-password",
|
|
316
|
+
const isMatch = verifyPassword("some-secure-password", result, salt);
|
|
316
317
|
console.log(`Password match: ${isMatch}`);
|
|
317
318
|
|
|
318
319
|
// Web example
|
|
319
320
|
import { hashPassword, verifyPassword } from "cipher-kit/web-api";
|
|
320
321
|
|
|
321
|
-
const {
|
|
322
|
-
console.log(`Hashed Password: ${
|
|
322
|
+
const { result, salt } = await hashPassword("some-secure-password");
|
|
323
|
+
console.log(`Hashed Password: ${result}`);
|
|
323
324
|
|
|
324
|
-
const isMatch = await verifyPassword("some-secure-password",
|
|
325
|
+
const isMatch = await verifyPassword("some-secure-password", result, salt);
|
|
325
326
|
console.log(`Password match: ${isMatch}`);
|
|
326
327
|
```
|
|
327
328
|
|
|
@@ -333,7 +334,7 @@ interface HashPasswordOptions {
|
|
|
333
334
|
digest?: "sha256" | "sha384" | "sha512";
|
|
334
335
|
|
|
335
336
|
// Encoding format for the output hash (default: "base64url").
|
|
336
|
-
|
|
337
|
+
outputEncoding?: "base64url" | "base64" | "hex";
|
|
337
338
|
|
|
338
339
|
// Length of the salt in bytes (default: 16 bytes, min: 8 bytes).
|
|
339
340
|
saltLength?: number;
|
|
@@ -350,7 +351,7 @@ interface VerifyPasswordOptions {
|
|
|
350
351
|
digest?: "sha256" | "sha384" | "sha512";
|
|
351
352
|
|
|
352
353
|
// Encoding format used during the original hashing (default: `'base64url'`).
|
|
353
|
-
|
|
354
|
+
inputEncoding?: "base64url" | "base64" | "hex";
|
|
354
355
|
|
|
355
356
|
// Number of iterations used during the original hashing (default: `320000`).
|
|
356
357
|
iterations?: number;
|
|
@@ -404,10 +405,10 @@ Regular expressions (regex) are sequences of characters that form search pattern
|
|
|
404
405
|
Before decrypting, you can validate the format (decryption functions already validate internally).
|
|
405
406
|
|
|
406
407
|
```typescript
|
|
407
|
-
import { ENCRYPTED_REGEX,
|
|
408
|
+
import { ENCRYPTED_REGEX, matchEncryptedPattern } from "cipher-kit"; // works in both "cipher-kit/web-api" and "cipher-kit/node"
|
|
408
409
|
|
|
409
410
|
function isEncryptedFormat(message: string): boolean {
|
|
410
|
-
return
|
|
411
|
+
return matchEncryptedPattern(message, "general"); // or "node" or "web"
|
|
411
412
|
}
|
|
412
413
|
|
|
413
414
|
// or
|
|
@@ -419,18 +420,15 @@ function isEncryptedFormat(message: string): boolean {
|
|
|
419
420
|
|
|
420
421
|
## Contributions 🤝
|
|
421
422
|
|
|
422
|
-
Want to contribute or suggest a feature?
|
|
423
|
+
Want to contribute or suggest a feature or improvement?
|
|
423
424
|
|
|
424
425
|
- Open an issue or feature request
|
|
425
426
|
- Submit a PR to improve the packages or add new ones
|
|
426
427
|
- Star ⭐ the repo if you like what you see
|
|
427
428
|
|
|
428
|
-
## License 📜
|
|
429
|
-
|
|
430
|
-
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
|
|
431
|
-
|
|
432
429
|
<div align="center">
|
|
433
430
|
<br/>
|
|
434
431
|
<div style="font-size: 14px; font-weight:bold;"> ⚒️ Crafted carefully by <a href="https://github.com/WolfieLeader" target="_blank" rel="nofollow">WolfieLeader</a></div>
|
|
435
|
-
<
|
|
432
|
+
<p style="font-size: 12px; font-style: italic;">This project is licensed under the <a href="https://opensource.org/licenses/MIT" target="_blank" rel="nofollow">MIT License</a>.</p>
|
|
433
|
+
<div style="font-size: 12px; font-style: italic; font-weight: 600;">Thank you!</div>
|
|
436
434
|
</div>
|
|
@@ -30,22 +30,22 @@ var ENCRYPTION_ALGORITHMS = Object.freeze({
|
|
|
30
30
|
function $isStr(x, min = 1) {
|
|
31
31
|
return x !== null && x !== void 0 && typeof x === "string" && x.trim().length >= min;
|
|
32
32
|
}
|
|
33
|
-
function $
|
|
33
|
+
function $isPlainObj(x) {
|
|
34
34
|
if (typeof x !== "object" || x === null || x === void 0) return false;
|
|
35
35
|
const proto = Object.getPrototypeOf(x);
|
|
36
36
|
return proto === Object.prototype || proto === null;
|
|
37
37
|
}
|
|
38
|
-
function $
|
|
38
|
+
function $isObj(x) {
|
|
39
39
|
return typeof x === "object" && x !== null && x !== void 0;
|
|
40
40
|
}
|
|
41
41
|
var expectedKeys = /* @__PURE__ */ new Set(["platform", "digest", "algorithm", "key"]);
|
|
42
42
|
function $isSecretKey(x, platform) {
|
|
43
|
-
if (!$
|
|
43
|
+
if (!$isObj(x) || platform !== "node" && platform !== "web" || x.platform !== platform) return null;
|
|
44
44
|
const keys = Object.keys(x);
|
|
45
45
|
if (keys.length !== expectedKeys.size) return null;
|
|
46
46
|
for (const key of keys) if (!expectedKeys.has(key)) return null;
|
|
47
47
|
for (const key of expectedKeys) if (!Object.hasOwn(x, key)) return null;
|
|
48
|
-
if (typeof x.digest !== "string" || !(x.digest in DIGEST_ALGORITHMS) || typeof x.algorithm !== "string" || !(x.algorithm in ENCRYPTION_ALGORITHMS) || !$
|
|
48
|
+
if (typeof x.digest !== "string" || !(x.digest in DIGEST_ALGORITHMS) || typeof x.algorithm !== "string" || !(x.algorithm in ENCRYPTION_ALGORITHMS) || !$isObj(x.key) || x.key.type !== "secret") {
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
51
51
|
const algorithm = ENCRYPTION_ALGORITHMS[x.algorithm];
|
|
@@ -55,7 +55,7 @@ function $isSecretKey(x, platform) {
|
|
|
55
55
|
}
|
|
56
56
|
return Object.freeze({ ...x, injected: algorithm });
|
|
57
57
|
}
|
|
58
|
-
if (!$
|
|
58
|
+
if (!$isObj(x.key.algorithm) || x.key.algorithm.name !== algorithm.web || typeof x.key.algorithm.length === "number" && x.key.algorithm.length !== algorithm.keyBytes * 8 || typeof x.key.extractable !== "boolean" || !Array.isArray(x.key.usages) || x.key.usages.length !== 2 || !(x.key.usages.includes("encrypt") && x.key.usages.includes("decrypt"))) {
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
61
|
return Object.freeze({ ...x, injected: algorithm });
|
|
@@ -65,7 +65,7 @@ var ENCRYPTED_REGEX = Object.freeze({
|
|
|
65
65
|
web: /^([^.]+)\.([^.]+)\.$/,
|
|
66
66
|
general: /^([^.]+)\.([^.]+)(?:\.([^.]+))?\.$/
|
|
67
67
|
});
|
|
68
|
-
function
|
|
68
|
+
function matchEncryptedPattern(data, format) {
|
|
69
69
|
if (typeof data !== "string") return false;
|
|
70
70
|
if (!(format in ENCRYPTED_REGEX)) throw new Error(`Unknown format: ${format}`);
|
|
71
71
|
return ENCRYPTED_REGEX[format].test(data);
|
|
@@ -73,7 +73,7 @@ function matchPattern(data, format) {
|
|
|
73
73
|
|
|
74
74
|
// src/helpers/error.ts
|
|
75
75
|
function $ok(result) {
|
|
76
|
-
if ($
|
|
76
|
+
if ($isPlainObj(result)) return { success: true, ...result };
|
|
77
77
|
return { success: true, result };
|
|
78
78
|
}
|
|
79
79
|
function $err(err) {
|
|
@@ -101,30 +101,31 @@ function title(platform, title2) {
|
|
|
101
101
|
// src/helpers/object.ts
|
|
102
102
|
function $stringifyObj(obj) {
|
|
103
103
|
try {
|
|
104
|
-
if (!$
|
|
104
|
+
if (!$isPlainObj(obj)) return $err({ msg: "Invalid object", desc: "Input is not a plain object" });
|
|
105
105
|
return $ok(JSON.stringify(obj));
|
|
106
106
|
} catch (error) {
|
|
107
107
|
return $err({ msg: "Utility: Stringify error", desc: $fmtError(error) });
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
function tryStringifyObj(obj) {
|
|
111
|
-
return $stringifyObj(obj);
|
|
112
|
-
}
|
|
113
|
-
function stringifyObj(obj) {
|
|
114
|
-
const { result, error } = $stringifyObj(obj);
|
|
115
|
-
if (error) throw new Error($fmtResultErr(error));
|
|
116
|
-
return result;
|
|
117
|
-
}
|
|
118
110
|
function $parseToObj(str) {
|
|
119
111
|
try {
|
|
120
112
|
if (!$isStr(str)) return $err({ msg: "Utility: Invalid input", desc: "Input is not a valid string" });
|
|
121
113
|
const obj = JSON.parse(str);
|
|
122
|
-
if (!$
|
|
114
|
+
if (!$isPlainObj(obj))
|
|
115
|
+
return $err({ msg: "Utility: Invalid object format", desc: "Parsed data is not a plain object" });
|
|
123
116
|
return $ok({ result: obj });
|
|
124
117
|
} catch (error) {
|
|
125
118
|
return $err({ msg: "Utility: Invalid format", desc: $fmtError(error) });
|
|
126
119
|
}
|
|
127
120
|
}
|
|
121
|
+
function tryStringifyObj(obj) {
|
|
122
|
+
return $stringifyObj(obj);
|
|
123
|
+
}
|
|
124
|
+
function stringifyObj(obj) {
|
|
125
|
+
const { result, error } = $stringifyObj(obj);
|
|
126
|
+
if (error) throw new Error($fmtResultErr(error));
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
128
129
|
function tryParseToObj(str) {
|
|
129
130
|
return $parseToObj(str);
|
|
130
131
|
}
|
|
@@ -137,6 +138,7 @@ function parseToObj(str) {
|
|
|
137
138
|
exports.$err = $err;
|
|
138
139
|
exports.$fmtError = $fmtError;
|
|
139
140
|
exports.$fmtResultErr = $fmtResultErr;
|
|
141
|
+
exports.$isPlainObj = $isPlainObj;
|
|
140
142
|
exports.$isSecretKey = $isSecretKey;
|
|
141
143
|
exports.$isStr = $isStr;
|
|
142
144
|
exports.$ok = $ok;
|
|
@@ -148,11 +150,11 @@ exports.ENCODING = ENCODING;
|
|
|
148
150
|
exports.ENCRYPTED_REGEX = ENCRYPTED_REGEX;
|
|
149
151
|
exports.ENCRYPTION_ALGORITHMS = ENCRYPTION_ALGORITHMS;
|
|
150
152
|
exports.__export = __export;
|
|
151
|
-
exports.
|
|
153
|
+
exports.matchEncryptedPattern = matchEncryptedPattern;
|
|
152
154
|
exports.parseToObj = parseToObj;
|
|
153
155
|
exports.stringifyObj = stringifyObj;
|
|
154
156
|
exports.title = title;
|
|
155
157
|
exports.tryParseToObj = tryParseToObj;
|
|
156
158
|
exports.tryStringifyObj = tryStringifyObj;
|
|
157
|
-
//# sourceMappingURL=chunk-
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
159
|
+
//# sourceMappingURL=chunk-BHG5RSUV.cjs.map
|
|
160
|
+
//# sourceMappingURL=chunk-BHG5RSUV.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/helpers/consts.ts","../src/helpers/validate.ts","../src/helpers/error.ts","../src/helpers/object.ts"],"names":["nodeCrypto","title"],"mappings":"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","file":"chunk-BHG5RSUV.cjs","sourcesContent":["export const ENCODING = Object.freeze([\"base64\", \"base64url\", \"hex\", \"utf8\", \"latin1\"] as const);\r\n\r\nexport const CIPHER_ENCODING = Object.freeze([\"base64\", \"base64url\", \"hex\"] as const);\r\n\r\nexport const DIGEST_ALGORITHMS = Object.freeze({\r\n sha256: { node: \"sha256\", web: \"SHA-256\" },\r\n sha384: { node: \"sha384\", web: \"SHA-384\" },\r\n sha512: { node: \"sha512\", web: \"SHA-512\" },\r\n} as const);\r\n\r\nexport const ENCRYPTION_ALGORITHMS = Object.freeze({\r\n aes256gcm: { keyBytes: 32, ivLength: 12, node: \"aes-256-gcm\", web: \"AES-GCM\" },\r\n aes192gcm: { keyBytes: 24, ivLength: 12, node: \"aes-192-gcm\", web: \"AES-GCM\" },\r\n aes128gcm: { keyBytes: 16, ivLength: 12, node: \"aes-128-gcm\", web: \"AES-GCM\" },\r\n} as const);\r\n","import nodeCrypto from \"node:crypto\";\r\nimport type { SecretKey } from \"~/helpers/types\";\r\nimport { DIGEST_ALGORITHMS, ENCRYPTION_ALGORITHMS } from \"./consts\";\r\n\r\nexport function $isStr(x: unknown, min = 1): x is string {\r\n return x !== null && x !== undefined && typeof x === \"string\" && x.trim().length >= min;\r\n}\r\n\r\nexport function $isPlainObj<T extends object = Record<string, unknown>>(x: unknown): x is T {\r\n if (typeof x !== \"object\" || x === null || x === undefined) return false;\r\n const proto = Object.getPrototypeOf(x);\r\n return proto === Object.prototype || proto === null;\r\n}\r\n\r\nexport function $isObj(x: unknown): x is Record<string, unknown> {\r\n return typeof x === \"object\" && x !== null && x !== undefined;\r\n}\r\n\r\ntype InjectedSecretKey<Platform extends \"web\" | \"node\"> = SecretKey<Platform> & {\r\n readonly injected: (typeof ENCRYPTION_ALGORITHMS)[keyof typeof ENCRYPTION_ALGORITHMS];\r\n};\r\n\r\nconst expectedKeys = new Set([\"platform\", \"digest\", \"algorithm\", \"key\"]);\r\n\r\nexport function $isSecretKey<Platform extends \"node\" | \"web\">(\r\n x: unknown,\r\n platform: Platform,\r\n): InjectedSecretKey<Platform> | null {\r\n if (!$isObj(x) || (platform !== \"node\" && platform !== \"web\") || x.platform !== platform) return null;\r\n\r\n const keys = Object.keys(x);\r\n if (keys.length !== expectedKeys.size) return null;\r\n for (const key of keys) if (!expectedKeys.has(key)) return null;\r\n for (const key of expectedKeys) if (!Object.hasOwn(x, key)) return null;\r\n\r\n if (\r\n typeof x.digest !== \"string\" ||\r\n !(x.digest in DIGEST_ALGORITHMS) ||\r\n typeof x.algorithm !== \"string\" ||\r\n !(x.algorithm in ENCRYPTION_ALGORITHMS) ||\r\n !$isObj(x.key) ||\r\n x.key.type !== \"secret\"\r\n ) {\r\n return null;\r\n }\r\n\r\n const algorithm = ENCRYPTION_ALGORITHMS[x.algorithm as keyof typeof ENCRYPTION_ALGORITHMS];\r\n\r\n if (platform === \"node\") {\r\n if (\r\n !(x.key instanceof nodeCrypto.KeyObject) ||\r\n (typeof x.key.symmetricKeySize === \"number\" && x.key.symmetricKeySize !== algorithm.keyBytes)\r\n ) {\r\n return null;\r\n }\r\n return Object.freeze({ ...x, injected: algorithm }) as InjectedSecretKey<Platform>;\r\n }\r\n\r\n if (\r\n !$isObj(x.key.algorithm) ||\r\n x.key.algorithm.name !== algorithm.web ||\r\n (typeof x.key.algorithm.length === \"number\" && x.key.algorithm.length !== algorithm.keyBytes * 8) ||\r\n typeof x.key.extractable !== \"boolean\" ||\r\n !Array.isArray(x.key.usages) ||\r\n x.key.usages.length !== 2 ||\r\n !(x.key.usages.includes(\"encrypt\") && x.key.usages.includes(\"decrypt\"))\r\n ) {\r\n return null;\r\n }\r\n return Object.freeze({ ...x, injected: algorithm }) as InjectedSecretKey<Platform>;\r\n}\r\n\r\n/**\r\n * Regular expressions for encrypted data patterns.\r\n *\r\n * - **node**: `\"iv.cipher.tag.\"` (three dot-separated parts plus a trailing dot)\r\n * - **web**: `\"iv.cipherWithTag.\"` (two parts plus a trailing dot)\r\n * - **general**: accepts both shapes (2 or 3 parts) with a trailing dot\r\n *\r\n * Each part is any non-empty string without dots.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You have a secret code you want to check. Before you check it,\r\n * you make sure it looks how a secret code should look.\r\n */\r\nexport const ENCRYPTED_REGEX = Object.freeze({\r\n node: /^([^.]+)\\.([^.]+)\\.([^.]+)\\.$/,\r\n web: /^([^.]+)\\.([^.]+)\\.$/,\r\n general: /^([^.]+)\\.([^.]+)(?:\\.([^.]+))?\\.$/,\r\n});\r\n\r\n/**\r\n * Checks if a string matches an expected encrypted payload shape.\r\n *\r\n * - **node**: `\"iv.cipher.tag.\"` (three dot-separated parts plus a trailing dot)\r\n * - **web**: `\"iv.cipherWithTag.\"` (two parts plus a trailing dot)\r\n * - **general**: accepts both shapes (2 or 3 parts) with a trailing dot\r\n *\r\n * Each part is any non-empty string without dots.\r\n *\r\n * This validates only the **shape**, not whether content is valid base64/hex, etc.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You have a secret code you want to check. Before you check it,\r\n * you make sure it looks how a secret code should look.\r\n *\r\n * @param data - The string to test.\r\n * @param format - Which layout to check: `'node'`, `'web'`, or `'general'`.\r\n * @returns `true` if the string matches the pattern; otherwise `false`.\r\n * @throws {Error} If an unknown `format` is provided.\r\n *\r\n * @example\r\n * ```ts\r\n * matchEncryptedPattern(\"abc.def.ghi.\", \"node\"); // true\r\n * matchEncryptedPattern(\"abc.def.\", \"web\"); // true\r\n * matchEncryptedPattern(\"abc.def.\", \"node\"); // false\r\n * matchEncryptedPattern(\"abc.def.ghi.\", \"general\"); // true\r\n * ```\r\n */\r\nexport function matchEncryptedPattern(data: string, format: \"general\" | \"node\" | \"web\"): boolean {\r\n if (typeof data !== \"string\") return false;\r\n if (!(format in ENCRYPTED_REGEX)) throw new Error(`Unknown format: ${format}`);\r\n return ENCRYPTED_REGEX[format].test(data);\r\n}\r\n","import { $isPlainObj } from \"./validate\";\r\n\r\n/**\r\n * Standardized error object for the `Result` type.\r\n * Always has a brief `message` and a more detailed `description`.\r\n */\r\nexport interface ResultErr {\r\n readonly message: string;\r\n readonly description: string;\r\n}\r\n\r\n/**\r\n * Discriminated union for functions that can succeed or fail.\r\n *\r\n * - On **success**:\r\n * - If `T` is an object - properties of `T` are **spread** into the result\r\n * along with `success: true`.\r\n * - Otherwise - `{ success: true, result: T }`.\r\n * - On **failure**: `{ success: false, error: E }`.\r\n *\r\n * @example\r\n * ```ts\r\n * // Primitive result\r\n * function getNum(): Result<number> {\r\n * return $ok(42);\r\n * }\r\n * const r1 = getNum();\r\n * if (r1.success) console.log(r1.result); // 42\r\n *\r\n * // Object result (spread)\r\n * function getObject(): Result<{ name: string; age: number }> {\r\n * return $ok({ name: 'Alice', age: 30 });\r\n * }\r\n * const r2 = getObject();\r\n * if (r2.success) console.log(r2.name, r2.age); // 'Alice' 30\r\n * ```\r\n */\r\nexport type Result<T, E = ResultErr> = T extends object\r\n ?\r\n | ({ readonly [K in keyof T]: T[K] } & { readonly success: true; readonly error?: undefined })\r\n | ({ readonly [K in keyof T]?: undefined } & { readonly success: false; readonly error: E })\r\n :\r\n | { readonly success: true; readonly result: T; readonly error?: undefined }\r\n | { readonly success: false; readonly error: E; readonly result?: undefined };\r\n\r\nexport function $ok<T>(result?: T): Result<T> {\r\n if ($isPlainObj(result)) return { success: true, ...(result as T & object) } as Result<T>;\r\n return { success: true, result } as Result<T>;\r\n}\r\n\r\nexport function $err(err: { msg: string; desc: string }): Result<never, ResultErr>;\r\nexport function $err(err: ResultErr): Result<never, ResultErr>;\r\nexport function $err(err: { msg: string; desc: string } | ResultErr): Result<never, ResultErr> {\r\n return {\r\n success: false,\r\n error: {\r\n message: \"msg\" in err ? err.msg : err.message,\r\n description: \"desc\" in err ? err.desc : err.description,\r\n },\r\n } as Result<never, ResultErr>;\r\n}\r\n\r\nexport function $fmtError(error: unknown): string {\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n return String(error);\r\n}\r\n\r\nexport function $fmtResultErr(err: ResultErr | undefined): string {\r\n if (!err) return \"Unknown error\";\r\n return `${err.message} - ${err.description}`;\r\n}\r\n\r\nexport function title(platform: \"web\" | \"node\", title: string): string {\r\n return `${platform === \"web\" ? \"Crypto Web API\" : \"Crypto NodeJS API\"} - ${title}`;\r\n}\r\n","import { $err, $fmtError, $fmtResultErr, $ok, type Result } from \"./error\";\r\nimport { $isPlainObj, $isStr } from \"./validate\";\r\n\r\nexport function $stringifyObj<T extends object = Record<string, unknown>>(obj: T): Result<string> {\r\n try {\r\n if (!$isPlainObj(obj)) return $err({ msg: \"Invalid object\", desc: \"Input is not a plain object\" });\r\n return $ok(JSON.stringify(obj));\r\n } catch (error) {\r\n return $err({ msg: \"Utility: Stringify error\", desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport function $parseToObj<T extends object = Record<string, unknown>>(str: string): Result<{ result: T }> {\r\n try {\r\n if (!$isStr(str)) return $err({ msg: \"Utility: Invalid input\", desc: \"Input is not a valid string\" });\r\n const obj = JSON.parse(str);\r\n\r\n if (!$isPlainObj(obj))\r\n return $err({ msg: \"Utility: Invalid object format\", desc: \"Parsed data is not a plain object\" });\r\n return $ok({ result: obj as T });\r\n } catch (error) {\r\n return $err({ msg: \"Utility: Invalid format\", desc: $fmtError(error) });\r\n }\r\n}\r\n\r\n/**\r\n * Safely serializes a plain object to JSON without throwing.\r\n *\r\n * Wraps `JSON.stringify` and returns a `Result` containing the JSON string or an error.\r\n * Only plain objects (POJOs) are accepted. Class instances, Maps, Sets, etc. are rejected.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You have a box of toys (your object) and take a photo of it (a JSON string)\r\n * so you can send it to a friend.\r\n *\r\n * @template T - Plain object type to serialize.\r\n * @param obj - The object to stringify (must be a plain object).\r\n * @returns A `Result` with the JSON string on success, or an error.\r\n *\r\n * @example\r\n * ```ts\r\n * const { result, error, success } = tryStringifyObj({ a: 1 });\r\n *\r\n * if (success) console.log(result); // \"{\\\"a\\\":1}\"\r\n * else console.error(error); // { message: \"...\", description: \"...\" }\r\n * ```\r\n */\r\nexport function tryStringifyObj<T extends object = Record<string, unknown>>(obj: T): Result<string> {\r\n return $stringifyObj(obj);\r\n}\r\n\r\n/**\r\n * Serializes a plain object to JSON (throwing).\r\n *\r\n * Wraps `JSON.stringify` and returns the result or throws an error.\r\n * Only plain objects (POJOs) are accepted. Class instances, Maps, Sets, etc. are rejected.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You have a box of toys (your object) and take a photo of it (a JSON string)\r\n * so you can send it to a friend.\r\n *\r\n * @template T - Plain object type to serialize.\r\n * @param obj - The object to stringify (must be a plain object).\r\n * @returns JSON string representation of the object.\r\n * @throws {Error} If `obj` is not a plain object or serialization fails.\r\n *\r\n * @example\r\n * ```ts\r\n * const json = stringifyObj({ a: 1 }); // \"{\\\"a\\\":1}\"\r\n * ```\r\n */\r\nexport function stringifyObj<T extends object = Record<string, unknown>>(obj: T): string {\r\n const { result, error } = $stringifyObj(obj);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely parses a JSON string to a plain object (non-throwing).\r\n *\r\n * Wraps `JSON.parse` and returns a `Result` containing the parsed object, or an error.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You rebuild your toy box (an object) from a photo you took (a JSON string).\r\n *\r\n * @template T - The expected object type.\r\n * @param str - The JSON string to parse.\r\n * @returns A `Result` with the parsed object on success, or an error.\r\n *\r\n * @example\r\n * ```ts\r\n * const {result, error, success} = tryParseToObj<{ a: number }>('{\"a\":1}');\r\n *\r\n * if (success) console.log(result); // { a: 1 }\r\n * else console.error(error) // { message: \"...\", description: \"...\" }\r\n * ```\r\n */\r\nexport function tryParseToObj<T extends object = Record<string, unknown>>(str: string): Result<{ result: T }> {\r\n return $parseToObj<T>(str);\r\n}\r\n\r\n/**\r\n * Parses a JSON string to a plain object (throwing).\r\n *\r\n * Wraps `JSON.parse` and returns the parsed object, or throws on failure.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You rebuild your toy box (an object) from a photo you took (a JSON string).\r\n *\r\n * @template T - The expected object type.\r\n * @param str - The JSON string to parse.\r\n * @returns The parsed plain object.\r\n * @throws {Error} If the string can’t be parsed or doesn’t represent a plain object.\r\n *\r\n * @example\r\n * ```ts\r\n * const obj = parseToObj<{ a: number }>('{\"a\":1}'); // obj.a === 1\r\n * ```\r\n */\r\nexport function parseToObj<T extends object = Record<string, unknown>>(str: string): T {\r\n const { result, error } = $parseToObj<T>(str);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export, $isSecretKey, $fmtResultErr, $ok, $err, $fmtError, title, $isStr, ENCRYPTION_ALGORITHMS, DIGEST_ALGORITHMS, CIPHER_ENCODING,
|
|
1
|
+
import { __export, $isSecretKey, $fmtResultErr, $ok, $err, $fmtError, title, $isStr, $isPlainObj, ENCRYPTION_ALGORITHMS, DIGEST_ALGORITHMS, CIPHER_ENCODING, matchEncryptedPattern, $stringifyObj, $parseToObj, ENCODING } from './chunk-RUTGDMVR.js';
|
|
2
2
|
|
|
3
3
|
// src/web/kit.ts
|
|
4
4
|
var kit_exports = {};
|
|
@@ -161,9 +161,18 @@ function $generateUuid() {
|
|
|
161
161
|
return $err({ msg: `${title("web", "UUID Generation")}: Failed to generate UUID`, desc: $fmtError(error) });
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
async function $createSecretKey(secret, options
|
|
165
|
-
if (!$isStr(secret)) {
|
|
166
|
-
return $err({
|
|
164
|
+
async function $createSecretKey(secret, options) {
|
|
165
|
+
if (!$isStr(secret, 8)) {
|
|
166
|
+
return $err({
|
|
167
|
+
msg: `${title("web", "Key Generation")}: Empty Secret`,
|
|
168
|
+
desc: "Secret must be a non-empty string with at least 8 characters"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (!$isPlainObj(options)) {
|
|
172
|
+
return $err({
|
|
173
|
+
msg: `${title("web", "Key Generation")}: Invalid options`,
|
|
174
|
+
desc: "Options must be an object"
|
|
175
|
+
});
|
|
167
176
|
}
|
|
168
177
|
const algorithm = options.algorithm ?? "aes256gcm";
|
|
169
178
|
if (!(algorithm in ENCRYPTION_ALGORITHMS)) {
|
|
@@ -225,17 +234,23 @@ async function $createSecretKey(secret, options = {}) {
|
|
|
225
234
|
});
|
|
226
235
|
}
|
|
227
236
|
}
|
|
228
|
-
async function $encrypt(data, secretKey, options
|
|
237
|
+
async function $encrypt(data, secretKey, options) {
|
|
229
238
|
if (!$isStr(data)) {
|
|
230
239
|
return $err({
|
|
231
240
|
msg: `${title("web", "Encryption")}: Empty data for encryption`,
|
|
232
241
|
desc: "Data must be a non-empty string"
|
|
233
242
|
});
|
|
234
243
|
}
|
|
235
|
-
|
|
236
|
-
if (!CIPHER_ENCODING.includes(encoding)) {
|
|
244
|
+
if (!$isPlainObj(options)) {
|
|
237
245
|
return $err({
|
|
238
|
-
msg: `${title("web", "Encryption")}:
|
|
246
|
+
msg: `${title("web", "Encryption")}: Invalid options`,
|
|
247
|
+
desc: "Options must be an object"
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const outputEncoding = options.outputEncoding ?? "base64url";
|
|
251
|
+
if (!CIPHER_ENCODING.includes(outputEncoding)) {
|
|
252
|
+
return $err({
|
|
253
|
+
msg: `${title("web", "Encryption")}: Unsupported output encoding: ${outputEncoding}`,
|
|
239
254
|
desc: "Use base64, base64url, or hex"
|
|
240
255
|
});
|
|
241
256
|
}
|
|
@@ -255,8 +270,8 @@ async function $encrypt(data, secretKey, options = {}) {
|
|
|
255
270
|
injectedKey.key,
|
|
256
271
|
result
|
|
257
272
|
);
|
|
258
|
-
const ivStr = $convertBytesToStr(iv,
|
|
259
|
-
const cipherStr = $convertBytesToStr(cipherWithTag,
|
|
273
|
+
const ivStr = $convertBytesToStr(iv, outputEncoding);
|
|
274
|
+
const cipherStr = $convertBytesToStr(cipherWithTag, outputEncoding);
|
|
260
275
|
if (ivStr.error || cipherStr.error) {
|
|
261
276
|
return $err({
|
|
262
277
|
msg: `${title("web", "Encryption")}: Failed to convert IV or encrypted data`,
|
|
@@ -268,17 +283,23 @@ async function $encrypt(data, secretKey, options = {}) {
|
|
|
268
283
|
return $err({ msg: `${title("web", "Encryption")}: Failed to encrypt data`, desc: $fmtError(error2) });
|
|
269
284
|
}
|
|
270
285
|
}
|
|
271
|
-
async function $decrypt(encrypted, secretKey, options
|
|
272
|
-
if (
|
|
286
|
+
async function $decrypt(encrypted, secretKey, options) {
|
|
287
|
+
if (!matchEncryptedPattern(encrypted, "web")) {
|
|
273
288
|
return $err({
|
|
274
289
|
msg: `${title("web", "Decryption")}: Invalid encrypted data format`,
|
|
275
290
|
desc: 'Encrypted data must be in the format "iv.cipherWithTag."'
|
|
276
291
|
});
|
|
277
292
|
}
|
|
278
|
-
|
|
279
|
-
if (!CIPHER_ENCODING.includes(encoding)) {
|
|
293
|
+
if (!$isPlainObj(options)) {
|
|
280
294
|
return $err({
|
|
281
|
-
msg: `${title("web", "Decryption")}:
|
|
295
|
+
msg: `${title("web", "Decryption")}: Invalid options`,
|
|
296
|
+
desc: "Options must be an object"
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
const inputEncoding = options.inputEncoding ?? "base64url";
|
|
300
|
+
if (!CIPHER_ENCODING.includes(inputEncoding)) {
|
|
301
|
+
return $err({
|
|
302
|
+
msg: `${title("web", "Decryption")}: Unsupported input encoding: ${inputEncoding}`,
|
|
282
303
|
desc: "Use base64, base64url, or hex"
|
|
283
304
|
});
|
|
284
305
|
}
|
|
@@ -296,8 +317,8 @@ async function $decrypt(encrypted, secretKey, options = {}) {
|
|
|
296
317
|
desc: "Expected a Web SecretKey"
|
|
297
318
|
});
|
|
298
319
|
}
|
|
299
|
-
const ivBytes = $convertStrToBytes(iv,
|
|
300
|
-
const cipherWithTagBytes = $convertStrToBytes(encryptedWithTag,
|
|
320
|
+
const ivBytes = $convertStrToBytes(iv, inputEncoding);
|
|
321
|
+
const cipherWithTagBytes = $convertStrToBytes(encryptedWithTag, inputEncoding);
|
|
301
322
|
if (ivBytes.error || cipherWithTagBytes.error) {
|
|
302
323
|
return $err({
|
|
303
324
|
msg: `${title("web", "Decryption")}: Failed to convert IV or encrypted data`,
|
|
@@ -315,24 +336,30 @@ async function $decrypt(encrypted, secretKey, options = {}) {
|
|
|
315
336
|
return $err({ msg: `${title("web", "Decryption")}: Failed to decrypt data`, desc: $fmtError(error) });
|
|
316
337
|
}
|
|
317
338
|
}
|
|
318
|
-
async function $encryptObj(data, secretKey, options
|
|
339
|
+
async function $encryptObj(data, secretKey, options) {
|
|
319
340
|
const { result, error } = $stringifyObj(data);
|
|
320
341
|
if (error) return $err(error);
|
|
321
342
|
return await $encrypt(result, secretKey, options);
|
|
322
343
|
}
|
|
323
|
-
async function $decryptObj(encrypted, secretKey, options
|
|
344
|
+
async function $decryptObj(encrypted, secretKey, options) {
|
|
324
345
|
const { result, error } = await $decrypt(encrypted, secretKey, options);
|
|
325
346
|
if (error) return $err(error);
|
|
326
347
|
return $parseToObj(result);
|
|
327
348
|
}
|
|
328
|
-
async function $hash(data, options
|
|
349
|
+
async function $hash(data, options) {
|
|
329
350
|
if (!$isStr(data)) {
|
|
330
351
|
return $err({ msg: `${title("web", "Hashing")}: Empty data for hashing`, desc: "Data must be a non-empty string" });
|
|
331
352
|
}
|
|
332
|
-
|
|
333
|
-
if (!CIPHER_ENCODING.includes(encoding)) {
|
|
353
|
+
if (!$isPlainObj(options)) {
|
|
334
354
|
return $err({
|
|
335
|
-
msg: `${title("web", "Hashing")}:
|
|
355
|
+
msg: `${title("web", "Hashing")}: Invalid options`,
|
|
356
|
+
desc: "Options must be an object"
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
const outputEncoding = options.outputEncoding ?? "base64url";
|
|
360
|
+
if (!CIPHER_ENCODING.includes(outputEncoding)) {
|
|
361
|
+
return $err({
|
|
362
|
+
msg: `${title("web", "Hashing")}: Unsupported output encoding: ${outputEncoding}`,
|
|
336
363
|
desc: "Use base64, base64url, or hex"
|
|
337
364
|
});
|
|
338
365
|
}
|
|
@@ -348,18 +375,24 @@ async function $hash(data, options = {}) {
|
|
|
348
375
|
if (error) return $err(error);
|
|
349
376
|
try {
|
|
350
377
|
const hashed = await crypto.subtle.digest(digestAlgo.web, result);
|
|
351
|
-
return $convertBytesToStr(hashed,
|
|
378
|
+
return $convertBytesToStr(hashed, outputEncoding);
|
|
352
379
|
} catch (error2) {
|
|
353
380
|
return $err({ msg: `${title("web", "Hashing")}: Failed to hash data`, desc: $fmtError(error2) });
|
|
354
381
|
}
|
|
355
382
|
}
|
|
356
|
-
async function $hashPassword(password, options
|
|
383
|
+
async function $hashPassword(password, options) {
|
|
357
384
|
if (!$isStr(password)) {
|
|
358
385
|
return $err({
|
|
359
386
|
msg: `${title("web", "Password Hashing")}: Empty password`,
|
|
360
387
|
desc: "Password must be a non-empty string"
|
|
361
388
|
});
|
|
362
389
|
}
|
|
390
|
+
if (!$isPlainObj(options)) {
|
|
391
|
+
return $err({
|
|
392
|
+
msg: `${title("web", "Password Hashing")}: Invalid options`,
|
|
393
|
+
desc: "Options must be an object"
|
|
394
|
+
});
|
|
395
|
+
}
|
|
363
396
|
const digest = options.digest ?? "sha512";
|
|
364
397
|
if (!(digest in DIGEST_ALGORITHMS)) {
|
|
365
398
|
return $err({
|
|
@@ -368,10 +401,10 @@ async function $hashPassword(password, options = {}) {
|
|
|
368
401
|
});
|
|
369
402
|
}
|
|
370
403
|
const digestAlgo = DIGEST_ALGORITHMS[digest];
|
|
371
|
-
const
|
|
372
|
-
if (!CIPHER_ENCODING.includes(
|
|
404
|
+
const outputEncoding = options.outputEncoding ?? "base64url";
|
|
405
|
+
if (!CIPHER_ENCODING.includes(outputEncoding)) {
|
|
373
406
|
return $err({
|
|
374
|
-
msg: `${title("web", "Password Hashing")}: Unsupported output encoding: ${
|
|
407
|
+
msg: `${title("web", "Password Hashing")}: Unsupported output encoding: ${outputEncoding}`,
|
|
375
408
|
desc: "Use base64, base64url, or hex"
|
|
376
409
|
});
|
|
377
410
|
}
|
|
@@ -410,29 +443,31 @@ async function $hashPassword(password, options = {}) {
|
|
|
410
443
|
baseKey,
|
|
411
444
|
keyLength * 8
|
|
412
445
|
);
|
|
413
|
-
const saltStr = $convertBytesToStr(salt,
|
|
446
|
+
const saltStr = $convertBytesToStr(salt, outputEncoding);
|
|
414
447
|
if (saltStr.error) return $err(saltStr.error);
|
|
415
|
-
const hashedPasswordStr = $convertBytesToStr(bits,
|
|
448
|
+
const hashedPasswordStr = $convertBytesToStr(bits, outputEncoding);
|
|
416
449
|
if (hashedPasswordStr.error) return $err(hashedPasswordStr.error);
|
|
417
|
-
return $ok({
|
|
450
|
+
return $ok({ result: hashedPasswordStr.result, salt: saltStr.result });
|
|
418
451
|
} catch (error) {
|
|
419
452
|
return $err({ msg: `${title("web", "Password Hashing")}: Failed to hash password`, desc: $fmtError(error) });
|
|
420
453
|
}
|
|
421
454
|
}
|
|
422
|
-
async function $verifyPassword(password, hashedPassword, salt, options
|
|
423
|
-
if (!$isStr(password) || !$isStr(hashedPassword) || !$isStr(salt))
|
|
455
|
+
async function $verifyPassword(password, hashedPassword, salt, options) {
|
|
456
|
+
if (!$isStr(password) || !$isStr(hashedPassword) || !$isStr(salt) || !$isPlainObj(options)) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
424
459
|
const digest = options.digest ?? "sha512";
|
|
425
460
|
if (!(digest in DIGEST_ALGORITHMS)) return false;
|
|
426
461
|
const digestAlgo = DIGEST_ALGORITHMS[digest];
|
|
427
|
-
const
|
|
428
|
-
if (!CIPHER_ENCODING.includes(
|
|
462
|
+
const inputEncoding = options.inputEncoding ?? "base64url";
|
|
463
|
+
if (!CIPHER_ENCODING.includes(inputEncoding)) return false;
|
|
429
464
|
const iterations = options.iterations ?? 32e4;
|
|
430
465
|
if (typeof iterations !== "number" || iterations < 1e3) return false;
|
|
431
466
|
const keyLength = options.keyLength ?? 64;
|
|
432
467
|
if (typeof keyLength !== "number" || keyLength < 16) return false;
|
|
433
|
-
const saltBytes = $convertStrToBytes(salt,
|
|
468
|
+
const saltBytes = $convertStrToBytes(salt, inputEncoding);
|
|
434
469
|
if (saltBytes.error) return false;
|
|
435
|
-
const hashedPasswordBytes = $convertStrToBytes(hashedPassword,
|
|
470
|
+
const hashedPasswordBytes = $convertStrToBytes(hashedPassword, inputEncoding);
|
|
436
471
|
if (hashedPasswordBytes.error) return false;
|
|
437
472
|
try {
|
|
438
473
|
const baseKey = await crypto.subtle.importKey(
|
|
@@ -530,9 +565,9 @@ async function tryHashPassword(password, options = {}) {
|
|
|
530
565
|
return await $hashPassword(password, options);
|
|
531
566
|
}
|
|
532
567
|
async function hashPassword(password, options = {}) {
|
|
533
|
-
const {
|
|
568
|
+
const { result, salt, error } = await $hashPassword(password, options);
|
|
534
569
|
if (error) throw new Error($fmtResultErr(error));
|
|
535
|
-
return {
|
|
570
|
+
return { result, salt };
|
|
536
571
|
}
|
|
537
572
|
async function verifyPassword(password, hashedPassword, salt, options = {}) {
|
|
538
573
|
return await $verifyPassword(password, hashedPassword, salt, options);
|
|
@@ -563,5 +598,5 @@ function convertEncoding(data, from, to) {
|
|
|
563
598
|
}
|
|
564
599
|
|
|
565
600
|
export { convertBytesToStr, convertEncoding, convertStrToBytes, createSecretKey, decrypt, decryptObj, encrypt, encryptObj, generateUuid, hash, hashPassword, isWebSecretKey, kit_exports, tryConvertBytesToStr, tryConvertEncoding, tryConvertStrToBytes, tryCreateSecretKey, tryDecrypt, tryDecryptObj, tryEncrypt, tryEncryptObj, tryGenerateUuid, tryHash, tryHashPassword, verifyPassword };
|
|
566
|
-
//# sourceMappingURL=chunk-
|
|
567
|
-
//# sourceMappingURL=chunk-
|
|
601
|
+
//# sourceMappingURL=chunk-CRTOKS3Q.js.map
|
|
602
|
+
//# sourceMappingURL=chunk-CRTOKS3Q.js.map
|