cipher-kit 2.1.3 → 3.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 +324 -434
- package/dist/chunk-3A4RTUKO.cjs +509 -0
- package/dist/chunk-3A4RTUKO.cjs.map +1 -0
- package/dist/chunk-7254PEID.cjs +502 -0
- package/dist/chunk-7254PEID.cjs.map +1 -0
- package/dist/chunk-GL32EZRA.js +475 -0
- package/dist/chunk-GL32EZRA.js.map +1 -0
- package/dist/chunk-IY6XGUYO.js +494 -0
- package/dist/chunk-IY6XGUYO.js.map +1 -0
- package/dist/chunk-VCBHSRCS.cjs +523 -0
- package/dist/chunk-VCBHSRCS.cjs.map +1 -0
- package/dist/chunk-X6MX4NDE.js +478 -0
- package/dist/chunk-X6MX4NDE.js.map +1 -0
- package/dist/export-B-3CCZIO.d.cts +389 -0
- package/dist/export-BPo6yPV-.d.ts +389 -0
- package/dist/export-C0_UEEg8.d.ts +396 -0
- package/dist/export-DPuocAr3.d.cts +396 -0
- package/dist/index.cjs +11 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -40
- package/dist/index.d.ts +11 -40
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +39 -35
- package/dist/node.d.cts +3 -3
- package/dist/node.d.ts +3 -3
- package/dist/node.js +2 -2
- package/dist/validate-vDTesb-X.d.cts +195 -0
- package/dist/validate-vDTesb-X.d.ts +195 -0
- package/dist/web-api.cjs +39 -35
- package/dist/web-api.d.cts +2 -3
- package/dist/web-api.d.ts +2 -3
- package/dist/web-api.js +2 -2
- package/package.json +82 -92
- package/dist/chunk-BMX42IZM.cjs +0 -623
- package/dist/chunk-BMX42IZM.cjs.map +0 -1
- package/dist/chunk-HTRGOBZF.cjs +0 -169
- package/dist/chunk-HTRGOBZF.cjs.map +0 -1
- package/dist/chunk-LU7QOSQH.js +0 -141
- package/dist/chunk-LU7QOSQH.js.map +0 -1
- package/dist/chunk-S6SNCTU6.js +0 -485
- package/dist/chunk-S6SNCTU6.js.map +0 -1
- package/dist/chunk-T36BEDPY.js +0 -598
- package/dist/chunk-T36BEDPY.js.map +0 -1
- package/dist/chunk-ZNM5M6RD.cjs +0 -514
- package/dist/chunk-ZNM5M6RD.cjs.map +0 -1
- package/dist/export-BaM_OTFk.d.ts +0 -573
- package/dist/export-CCTGAosO.d.ts +0 -572
- package/dist/export-FYHgb-8E.d.cts +0 -572
- package/dist/export-KFT0YyMg.d.cts +0 -573
- package/dist/validate-lkJAHCeJ.d.cts +0 -399
- package/dist/validate-lkJAHCeJ.d.ts +0 -399
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __export = (target, all) => {
|
|
5
|
+
for (var name in all)
|
|
6
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// ../internal-helpers/dist/index.js
|
|
10
|
+
function $isStr(x, min = 1) {
|
|
11
|
+
return typeof x === "string" && x.trim().length >= min;
|
|
12
|
+
}
|
|
13
|
+
function $isIntIn(x, min, max) {
|
|
14
|
+
return typeof x === "number" && Number.isInteger(x) && x >= min && x <= max;
|
|
15
|
+
}
|
|
16
|
+
function $isPlainObj(x) {
|
|
17
|
+
if (typeof x !== "object" || x === null) return false;
|
|
18
|
+
const proto = Object.getPrototypeOf(x);
|
|
19
|
+
return proto === Object.prototype || proto === null;
|
|
20
|
+
}
|
|
21
|
+
function $ok(result) {
|
|
22
|
+
if ($isPlainObj(result)) {
|
|
23
|
+
const obj = result;
|
|
24
|
+
if (Object.hasOwn(obj, "success") || Object.hasOwn(obj, "error")) {
|
|
25
|
+
return { success: true, result };
|
|
26
|
+
}
|
|
27
|
+
return { success: true, ...obj };
|
|
28
|
+
}
|
|
29
|
+
return { success: true, result };
|
|
30
|
+
}
|
|
31
|
+
function $err(err) {
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
error: { message: err.message, description: err.description }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function $fmtError(error) {
|
|
38
|
+
if (typeof error === "string") return error;
|
|
39
|
+
if (error instanceof Error) return error.message;
|
|
40
|
+
return String(error);
|
|
41
|
+
}
|
|
42
|
+
function $fmtResultErr(err) {
|
|
43
|
+
if (!err) return "Unknown error";
|
|
44
|
+
return `${err.message} - ${err.description}`;
|
|
45
|
+
}
|
|
46
|
+
var textEncoder = new TextEncoder();
|
|
47
|
+
new TextDecoder();
|
|
48
|
+
var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
49
|
+
var ENCODING = Object.freeze(["base64", "base64url", "hex", "utf8", "latin1"]);
|
|
50
|
+
var CIPHER_ENCODING = Object.freeze(["base64", "base64url", "hex"]);
|
|
51
|
+
function $convertStrToBytes(data, inputEncoding = "utf8") {
|
|
52
|
+
if (typeof data !== "string") {
|
|
53
|
+
return $err({
|
|
54
|
+
message: "strToBytes: Data must be a string",
|
|
55
|
+
description: `Expected a string value, received ${typeof data}`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (!ENCODING.includes(inputEncoding)) {
|
|
59
|
+
return $err({
|
|
60
|
+
message: `strToBytes: Unsupported encoding: ${inputEncoding}`,
|
|
61
|
+
description: "Use base64, base64url, hex, utf8, or latin1"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const bytes = strToBytes[inputEncoding](data);
|
|
66
|
+
return $ok({ result: bytes });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return $err({ message: "strToBytes: Failed to convert data", description: $fmtError(error) });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function $convertBytesToStr(data, outputEncoding = "utf8") {
|
|
72
|
+
if (!(data instanceof ArrayBuffer || data instanceof Uint8Array)) {
|
|
73
|
+
return $err({
|
|
74
|
+
message: "bytesToStr: Data must be an ArrayBuffer or Uint8Array",
|
|
75
|
+
description: `Expected binary data (ArrayBuffer or Uint8Array), received ${typeof data}`
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (!ENCODING.includes(outputEncoding)) {
|
|
79
|
+
return $err({
|
|
80
|
+
message: `bytesToStr: Unsupported encoding: ${outputEncoding}`,
|
|
81
|
+
description: "Use base64, base64url, hex, utf8, or latin1"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
86
|
+
const str = bytesToStr[outputEncoding](bytes);
|
|
87
|
+
return $ok(str);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return $err({ message: "bytesToStr: Failed to convert data", description: $fmtError(error) });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
var strToBytes = {
|
|
93
|
+
base64: $fromBase64,
|
|
94
|
+
base64url: $fromBase64Url,
|
|
95
|
+
hex: $fromHex,
|
|
96
|
+
latin1: $fromLatin1,
|
|
97
|
+
utf8: (data) => textEncoder.encode(data)
|
|
98
|
+
};
|
|
99
|
+
var bytesToStr = {
|
|
100
|
+
base64: $toBase64,
|
|
101
|
+
base64url: $toBase64Url,
|
|
102
|
+
hex: $toHex,
|
|
103
|
+
latin1: $toLatin1,
|
|
104
|
+
utf8: (data) => strictUtf8Decoder.decode(data)
|
|
105
|
+
};
|
|
106
|
+
function $toLatin1(bytes) {
|
|
107
|
+
let out = "";
|
|
108
|
+
const chunk = 1 << 15;
|
|
109
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
110
|
+
out += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
function $fromLatin1(data) {
|
|
115
|
+
const out = new Uint8Array(data.length);
|
|
116
|
+
for (let i = 0; i < data.length; i++) {
|
|
117
|
+
const charCode = data.charCodeAt(i);
|
|
118
|
+
if (charCode > 255) throw new Error("Invalid latin1 string");
|
|
119
|
+
out[i] = charCode;
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
function $toBase64(bytes) {
|
|
124
|
+
return btoa($toLatin1(bytes));
|
|
125
|
+
}
|
|
126
|
+
var BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}={2}|[A-Za-z0-9+/]{3}=)?$/;
|
|
127
|
+
function $fromBase64(data) {
|
|
128
|
+
if (!BASE64_REGEX.test(data)) throw new Error("Invalid base64 string");
|
|
129
|
+
return $fromLatin1(atob(data));
|
|
130
|
+
}
|
|
131
|
+
function $toBase64Url(bytes) {
|
|
132
|
+
return $toBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
133
|
+
}
|
|
134
|
+
var BASE64URL_REGEX = /^[A-Za-z0-9_-]*={0,2}$/;
|
|
135
|
+
function $fromBase64Url(data) {
|
|
136
|
+
if (!BASE64URL_REGEX.test(data) || data.replace(/=+$/, "").length % 4 === 1) {
|
|
137
|
+
throw new Error("Invalid base64url string");
|
|
138
|
+
}
|
|
139
|
+
let base64 = data.replace(/-/g, "+").replace(/_/g, "/");
|
|
140
|
+
const padLen = (4 - base64.length % 4) % 4;
|
|
141
|
+
base64 += "=".repeat(padLen);
|
|
142
|
+
return $fromBase64(base64);
|
|
143
|
+
}
|
|
144
|
+
var HEX_TABLE = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
145
|
+
var HEX_NIBBLE = new Uint8Array(256).fill(255);
|
|
146
|
+
for (let i = 48; i <= 57; i++) HEX_NIBBLE[i] = i - 48;
|
|
147
|
+
for (let i = 65; i <= 70; i++) HEX_NIBBLE[i] = i - 55;
|
|
148
|
+
for (let i = 97; i <= 102; i++) HEX_NIBBLE[i] = i - 87;
|
|
149
|
+
function $toHex(bytes) {
|
|
150
|
+
const hex = new Array(bytes.length);
|
|
151
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
152
|
+
hex[i] = HEX_TABLE[bytes[i]];
|
|
153
|
+
}
|
|
154
|
+
return hex.join("");
|
|
155
|
+
}
|
|
156
|
+
function $fromHex(data) {
|
|
157
|
+
const clean = data.startsWith("0x") || data.startsWith("0X") ? data.slice(2) : data;
|
|
158
|
+
if (clean.length % 2 !== 0) throw new Error("Invalid hex string");
|
|
159
|
+
const out = new Uint8Array(clean.length / 2);
|
|
160
|
+
for (let i = 0, j = 0; i < clean.length; i += 2, j++) {
|
|
161
|
+
const hiCode = clean.charCodeAt(i);
|
|
162
|
+
const loCode = clean.charCodeAt(i + 1);
|
|
163
|
+
if (hiCode > 255 || loCode > 255) throw new Error("Invalid hex string");
|
|
164
|
+
const hi = HEX_NIBBLE[hiCode];
|
|
165
|
+
const lo = HEX_NIBBLE[loCode];
|
|
166
|
+
if (hi === 255 || lo === 255) throw new Error("Invalid hex string");
|
|
167
|
+
out[j] = hi << 4 | lo;
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
var ProtoTraversalLimitError = class extends Error {
|
|
172
|
+
constructor(limit) {
|
|
173
|
+
super(`Object graph exceeded prototype-scan limit (${limit} nodes)`);
|
|
174
|
+
this.name = "ProtoTraversalLimitError";
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var MAX_PROTO_SCAN_NODES = 1e5;
|
|
178
|
+
function $hasProtoKey(obj) {
|
|
179
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
180
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
181
|
+
const stack = [obj];
|
|
182
|
+
let scannedNodes = 0;
|
|
183
|
+
while (stack.length > 0) {
|
|
184
|
+
const current = stack.pop();
|
|
185
|
+
if (typeof current !== "object" || current === null) continue;
|
|
186
|
+
if (seen.has(current)) continue;
|
|
187
|
+
seen.add(current);
|
|
188
|
+
scannedNodes++;
|
|
189
|
+
if (scannedNodes > MAX_PROTO_SCAN_NODES) {
|
|
190
|
+
throw new ProtoTraversalLimitError(MAX_PROTO_SCAN_NODES);
|
|
191
|
+
}
|
|
192
|
+
if (Object.hasOwn(current, "__proto__")) return true;
|
|
193
|
+
const currentObj = current;
|
|
194
|
+
if (Object.hasOwn(currentObj, "constructor") && typeof currentObj.constructor === "object" && currentObj.constructor !== null && Object.hasOwn(currentObj.constructor, "prototype") && typeof currentObj.constructor.prototype === "object" && currentObj.constructor.prototype !== null) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
for (const val of Object.values(currentObj)) {
|
|
198
|
+
if (typeof val === "object" && val !== null) {
|
|
199
|
+
stack.push(val);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
function $stringifyObj(obj) {
|
|
206
|
+
if (!$isPlainObj(obj))
|
|
207
|
+
return $err({
|
|
208
|
+
message: "stringifyObj: Input must be a plain object",
|
|
209
|
+
description: "Only plain objects ({...}) are accepted, not arrays, class instances, or built-ins"
|
|
210
|
+
});
|
|
211
|
+
try {
|
|
212
|
+
return $ok(JSON.stringify(obj));
|
|
213
|
+
} catch (error) {
|
|
214
|
+
return $err({ message: "stringifyObj: Failed to stringify object", description: $fmtError(error) });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function $parseToObj(str) {
|
|
218
|
+
if (!$isStr(str))
|
|
219
|
+
return $err({
|
|
220
|
+
message: "parseToObj: Input must be a non-empty string",
|
|
221
|
+
description: "Expected a non-empty JSON string to parse"
|
|
222
|
+
});
|
|
223
|
+
try {
|
|
224
|
+
const obj = JSON.parse(str);
|
|
225
|
+
if (!$isPlainObj(obj)) {
|
|
226
|
+
return $err({
|
|
227
|
+
message: "parseToObj: Parsed data is not a plain object",
|
|
228
|
+
description: "JSON parsed successfully but the result is not a plain object (e.g. array, string, number)"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if ($hasProtoKey(obj)) {
|
|
232
|
+
return $err({
|
|
233
|
+
message: "parseToObj: Input contains a prototype pollution vector",
|
|
234
|
+
description: "Objects with __proto__ or constructor.prototype keys are rejected"
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return $ok({ result: obj });
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (error instanceof ProtoTraversalLimitError) {
|
|
240
|
+
return $err({
|
|
241
|
+
message: "parseToObj: Input object is too deeply nested to validate safely",
|
|
242
|
+
description: error.message
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return $err({ message: "parseToObj: Failed to parse JSON", description: $fmtError(error) });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/helpers/consts.ts
|
|
250
|
+
var GCM_TAG_BYTES = 16;
|
|
251
|
+
var GCM_IV_LENGTH = 12;
|
|
252
|
+
var MAX_PBKDF2_ITERATIONS = 1e7;
|
|
253
|
+
var MAX_PBKDF2_KEY_LENGTH = 1024;
|
|
254
|
+
var MAX_PBKDF2_SALT_LENGTH = 1024;
|
|
255
|
+
var DIGEST_ALGORITHMS = Object.freeze({
|
|
256
|
+
sha256: { node: "sha256", web: "SHA-256" },
|
|
257
|
+
sha384: { node: "sha384", web: "SHA-384" },
|
|
258
|
+
sha512: { node: "sha512", web: "SHA-512" }
|
|
259
|
+
});
|
|
260
|
+
var ENCRYPTION_ALGORITHMS = Object.freeze({
|
|
261
|
+
aes256gcm: { keyBytes: 32, node: "aes-256-gcm", web: "AES-GCM" },
|
|
262
|
+
aes192gcm: { keyBytes: 24, node: "aes-192-gcm", web: "AES-GCM" },
|
|
263
|
+
aes128gcm: { keyBytes: 16, node: "aes-128-gcm", web: "AES-GCM" }
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// src/helpers/validate.ts
|
|
267
|
+
function $isObj(x) {
|
|
268
|
+
return typeof x === "object" && x !== null;
|
|
269
|
+
}
|
|
270
|
+
var expectedKeys = /* @__PURE__ */ new Set(["platform", "digest", "algorithm", "key", "injected"]);
|
|
271
|
+
function $validateSecretKeyBase(x, platform) {
|
|
272
|
+
if (!$isObj(x) || platform !== "node" && platform !== "web" || x.platform !== platform) return null;
|
|
273
|
+
const keys = Object.keys(x);
|
|
274
|
+
if (keys.length !== expectedKeys.size) return null;
|
|
275
|
+
for (const key of keys) if (!expectedKeys.has(key)) return null;
|
|
276
|
+
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") {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const algorithm = ENCRYPTION_ALGORITHMS[x.algorithm];
|
|
280
|
+
if (!$isObj(x.injected) || x.injected.keyBytes !== algorithm.keyBytes || x.injected.node !== algorithm.node || x.injected.web !== algorithm.web) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
return { obj: x, algorithm };
|
|
284
|
+
}
|
|
285
|
+
var ENCRYPTED_REGEX = /^([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\.([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\.([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\.$/;
|
|
286
|
+
function matchEncryptedPattern(data) {
|
|
287
|
+
return typeof data === "string" && ENCRYPTED_REGEX.test(data);
|
|
288
|
+
}
|
|
289
|
+
function $validateCreateSecretKeyOptions(secret, options, prefix) {
|
|
290
|
+
if (!$isStr(secret, 8)) {
|
|
291
|
+
return $err({
|
|
292
|
+
message: `${prefix} createSecretKey: Secret must be at least 8 characters`,
|
|
293
|
+
description: "Use a high-entropy string of at least 8 characters"
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
if (!$isPlainObj(options)) {
|
|
297
|
+
return $err({
|
|
298
|
+
message: `${prefix} createSecretKey: Options must be a plain object`,
|
|
299
|
+
description: 'Pass an object like { algorithm: "aes256gcm" }'
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const algorithm = options.algorithm ?? "aes256gcm";
|
|
303
|
+
if (!(algorithm in ENCRYPTION_ALGORITHMS)) {
|
|
304
|
+
return $err({
|
|
305
|
+
message: `${prefix} createSecretKey: Unsupported algorithm: ${algorithm}`,
|
|
306
|
+
description: `Supported algorithms are: ${Object.keys(ENCRYPTION_ALGORITHMS).join(", ")}`
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
const digest = options.digest ?? "sha256";
|
|
310
|
+
if (!(digest in DIGEST_ALGORITHMS)) {
|
|
311
|
+
return $err({
|
|
312
|
+
message: `${prefix} createSecretKey: Unsupported digest: ${digest}`,
|
|
313
|
+
description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
const salt = options.salt ?? "cipher-kit";
|
|
317
|
+
if (!$isStr(salt, 8)) {
|
|
318
|
+
return $err({
|
|
319
|
+
message: `${prefix} createSecretKey: Salt must be at least 8 characters`,
|
|
320
|
+
description: "Provide a salt string with at least 8 characters"
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const info = options.info ?? "cipher-kit";
|
|
324
|
+
if (!$isStr(info)) {
|
|
325
|
+
return $err({
|
|
326
|
+
message: `${prefix} createSecretKey: Info must be a non-empty string`,
|
|
327
|
+
description: "Received empty or non-string value"
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return $ok({
|
|
331
|
+
algorithm,
|
|
332
|
+
digest,
|
|
333
|
+
salt,
|
|
334
|
+
info,
|
|
335
|
+
encryptAlgo: ENCRYPTION_ALGORITHMS[algorithm],
|
|
336
|
+
digestAlgo: DIGEST_ALGORITHMS[digest]
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
function $validateHashPasswordOptions(password, options, prefix) {
|
|
340
|
+
if (!$isStr(password)) {
|
|
341
|
+
return $err({
|
|
342
|
+
message: `${prefix} hashPassword: Password must be a non-empty string`,
|
|
343
|
+
description: "Received empty or non-string value"
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
if (!$isPlainObj(options)) {
|
|
347
|
+
return $err({
|
|
348
|
+
message: `${prefix} hashPassword: Options must be a plain object`,
|
|
349
|
+
description: "Pass an object like { iterations: 320000 }"
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const digest = options.digest ?? "sha512";
|
|
353
|
+
if (!(digest in DIGEST_ALGORITHMS)) {
|
|
354
|
+
return $err({
|
|
355
|
+
message: `${prefix} hashPassword: Unsupported digest: ${digest}`,
|
|
356
|
+
description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
const outputEncoding = options.outputEncoding ?? "base64url";
|
|
360
|
+
if (!CIPHER_ENCODING.includes(outputEncoding)) {
|
|
361
|
+
return $err({
|
|
362
|
+
message: `${prefix} hashPassword: Unsupported output encoding: ${outputEncoding}`,
|
|
363
|
+
description: "Use base64, base64url, or hex"
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const saltLength = options.saltLength ?? 16;
|
|
367
|
+
if (!$isIntIn(saltLength, 8, MAX_PBKDF2_SALT_LENGTH)) {
|
|
368
|
+
return $err({
|
|
369
|
+
message: `${prefix} hashPassword: Salt length must be at least 8 bytes`,
|
|
370
|
+
description: `Must be an integer between 8 and ${MAX_PBKDF2_SALT_LENGTH} (recommended 16 or more)`
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
const iterations = options.iterations ?? 32e4;
|
|
374
|
+
if (!$isIntIn(iterations, 1e5, MAX_PBKDF2_ITERATIONS)) {
|
|
375
|
+
return $err({
|
|
376
|
+
message: `${prefix} hashPassword: Iterations must be at least 100,000`,
|
|
377
|
+
description: `Must be an integer between 100,000 and ${MAX_PBKDF2_ITERATIONS} (recommended 320,000 or more)`
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
const keyLength = options.keyLength ?? 64;
|
|
381
|
+
if (!$isIntIn(keyLength, 16, MAX_PBKDF2_KEY_LENGTH)) {
|
|
382
|
+
return $err({
|
|
383
|
+
message: `${prefix} hashPassword: Key length must be at least 16 bytes`,
|
|
384
|
+
description: `Must be an integer between 16 and ${MAX_PBKDF2_KEY_LENGTH} (recommended 64 or more)`
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
return $ok({
|
|
388
|
+
digest,
|
|
389
|
+
digestAlgo: DIGEST_ALGORITHMS[digest],
|
|
390
|
+
outputEncoding,
|
|
391
|
+
saltLength,
|
|
392
|
+
iterations,
|
|
393
|
+
keyLength
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
function $maxEncodedLength(byteLength, encoding) {
|
|
397
|
+
if (encoding === "hex") return byteLength * 2;
|
|
398
|
+
return Math.ceil(byteLength / 3) * 4;
|
|
399
|
+
}
|
|
400
|
+
function $validateVerifyPasswordOptions(password, hashedPassword, salt, options, prefix) {
|
|
401
|
+
if (!$isStr(password)) {
|
|
402
|
+
return $err({
|
|
403
|
+
message: `${prefix} verifyPassword: Password must be a non-empty string`,
|
|
404
|
+
description: "Received empty or non-string value"
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (!$isStr(hashedPassword)) {
|
|
408
|
+
return $err({
|
|
409
|
+
message: `${prefix} verifyPassword: Hashed password must be a non-empty string`,
|
|
410
|
+
description: "Pass the hash string returned by hashPassword()"
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
if (!$isStr(salt)) {
|
|
414
|
+
return $err({
|
|
415
|
+
message: `${prefix} verifyPassword: Salt must be a non-empty string`,
|
|
416
|
+
description: "Pass the salt string returned by hashPassword()"
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
if (!$isPlainObj(options)) {
|
|
420
|
+
return $err({
|
|
421
|
+
message: `${prefix} verifyPassword: Options must be a plain object`,
|
|
422
|
+
description: "Pass an object matching the options used for hashPassword()"
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
const digest = options.digest ?? "sha512";
|
|
426
|
+
if (!(digest in DIGEST_ALGORITHMS)) {
|
|
427
|
+
return $err({
|
|
428
|
+
message: `${prefix} verifyPassword: Unsupported digest: ${digest}`,
|
|
429
|
+
description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
const inputEncoding = options.inputEncoding ?? "base64url";
|
|
433
|
+
if (!CIPHER_ENCODING.includes(inputEncoding)) {
|
|
434
|
+
return $err({
|
|
435
|
+
message: `${prefix} verifyPassword: Unsupported input encoding: ${inputEncoding}`,
|
|
436
|
+
description: "Use base64, base64url, or hex"
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
const iterations = options.iterations ?? 32e4;
|
|
440
|
+
if (!$isIntIn(iterations, 1e5, MAX_PBKDF2_ITERATIONS)) {
|
|
441
|
+
return $err({
|
|
442
|
+
message: `${prefix} verifyPassword: Iterations must be at least 100,000`,
|
|
443
|
+
description: `Must be an integer between 100,000 and ${MAX_PBKDF2_ITERATIONS}`
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
const keyLength = options.keyLength ?? 64;
|
|
447
|
+
if (!$isIntIn(keyLength, 16, MAX_PBKDF2_KEY_LENGTH)) {
|
|
448
|
+
return $err({
|
|
449
|
+
message: `${prefix} verifyPassword: Key length must be at least 16 bytes`,
|
|
450
|
+
description: `Must be an integer between 16 and ${MAX_PBKDF2_KEY_LENGTH}`
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
const maxHashLen = $maxEncodedLength(keyLength, inputEncoding);
|
|
454
|
+
if (hashedPassword.length > maxHashLen) {
|
|
455
|
+
return $err({
|
|
456
|
+
message: `${prefix} verifyPassword: Hashed password exceeds maximum encoded length`,
|
|
457
|
+
description: `Expected at most ${maxHashLen} characters for ${keyLength}-byte key with ${inputEncoding} encoding`
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const maxSaltLen = $maxEncodedLength(MAX_PBKDF2_SALT_LENGTH, inputEncoding);
|
|
461
|
+
if (salt.length > maxSaltLen) {
|
|
462
|
+
return $err({
|
|
463
|
+
message: `${prefix} verifyPassword: Salt exceeds maximum encoded length`,
|
|
464
|
+
description: `Expected at most ${maxSaltLen} characters for ${inputEncoding} encoding`
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
return $ok({
|
|
468
|
+
digest,
|
|
469
|
+
digestAlgo: DIGEST_ALGORITHMS[digest],
|
|
470
|
+
inputEncoding,
|
|
471
|
+
iterations,
|
|
472
|
+
keyLength
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/helpers/object.ts
|
|
477
|
+
function tryStringifyObj(obj) {
|
|
478
|
+
return $stringifyObj(obj);
|
|
479
|
+
}
|
|
480
|
+
function stringifyObj(obj) {
|
|
481
|
+
const { result, error } = $stringifyObj(obj);
|
|
482
|
+
if (error) throw new Error($fmtResultErr(error));
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
function tryParseToObj(str) {
|
|
486
|
+
return $parseToObj(str);
|
|
487
|
+
}
|
|
488
|
+
function parseToObj(str) {
|
|
489
|
+
const { result, error } = $parseToObj(str);
|
|
490
|
+
if (error) throw new Error($fmtResultErr(error));
|
|
491
|
+
return result;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
exports.$convertBytesToStr = $convertBytesToStr;
|
|
495
|
+
exports.$convertStrToBytes = $convertStrToBytes;
|
|
496
|
+
exports.$err = $err;
|
|
497
|
+
exports.$fmtError = $fmtError;
|
|
498
|
+
exports.$fmtResultErr = $fmtResultErr;
|
|
499
|
+
exports.$isObj = $isObj;
|
|
500
|
+
exports.$isPlainObj = $isPlainObj;
|
|
501
|
+
exports.$isStr = $isStr;
|
|
502
|
+
exports.$ok = $ok;
|
|
503
|
+
exports.$parseToObj = $parseToObj;
|
|
504
|
+
exports.$stringifyObj = $stringifyObj;
|
|
505
|
+
exports.$validateCreateSecretKeyOptions = $validateCreateSecretKeyOptions;
|
|
506
|
+
exports.$validateHashPasswordOptions = $validateHashPasswordOptions;
|
|
507
|
+
exports.$validateSecretKeyBase = $validateSecretKeyBase;
|
|
508
|
+
exports.$validateVerifyPasswordOptions = $validateVerifyPasswordOptions;
|
|
509
|
+
exports.CIPHER_ENCODING = CIPHER_ENCODING;
|
|
510
|
+
exports.DIGEST_ALGORITHMS = DIGEST_ALGORITHMS;
|
|
511
|
+
exports.ENCODING = ENCODING;
|
|
512
|
+
exports.ENCRYPTED_REGEX = ENCRYPTED_REGEX;
|
|
513
|
+
exports.GCM_IV_LENGTH = GCM_IV_LENGTH;
|
|
514
|
+
exports.GCM_TAG_BYTES = GCM_TAG_BYTES;
|
|
515
|
+
exports.__export = __export;
|
|
516
|
+
exports.matchEncryptedPattern = matchEncryptedPattern;
|
|
517
|
+
exports.parseToObj = parseToObj;
|
|
518
|
+
exports.stringifyObj = stringifyObj;
|
|
519
|
+
exports.textEncoder = textEncoder;
|
|
520
|
+
exports.tryParseToObj = tryParseToObj;
|
|
521
|
+
exports.tryStringifyObj = tryStringifyObj;
|
|
522
|
+
//# sourceMappingURL=chunk-VCBHSRCS.cjs.map
|
|
523
|
+
//# sourceMappingURL=chunk-VCBHSRCS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../internal-helpers/src/validate.ts","../../internal-helpers/src/error.ts","../../internal-helpers/src/encode.ts","../../internal-helpers/src/object.ts","../src/helpers/consts.ts","../src/helpers/validate.ts","../src/helpers/object.ts"],"names":[],"mappings":"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","file":"chunk-VCBHSRCS.cjs","sourcesContent":["export function $isStr(x: unknown, min = 1): x is string {\n return typeof x === \"string\" && x.trim().length >= min;\n}\n\nexport function $isIntIn<T extends number>(x: unknown, min: number, max: number): x is T {\n return typeof x === \"number\" && Number.isInteger(x) && x >= min && x <= max;\n}\n\nexport function $isPlainObj<T extends object = Record<string, unknown>>(x: unknown): x is T {\n if (typeof x !== \"object\" || x === null) return false;\n const proto = Object.getPrototypeOf(x);\n return proto === Object.prototype || proto === null;\n}\n","import { $isPlainObj } from \"./validate.js\";\n\nexport interface ErrorStruct {\n readonly message: string;\n readonly description: string;\n}\n\ntype ReservedResultKeys = \"success\" | \"error\";\n\ntype ShouldWrapObject<T extends object> = Extract<keyof T, ReservedResultKeys> extends never ? false : true;\n\ntype OkType<T> = {\n readonly success: true;\n readonly error?: undefined;\n} & (T extends object\n ? ShouldWrapObject<T> extends true\n ? { readonly result: T }\n : { readonly [K in keyof T]: T[K] }\n : { readonly result: T });\n\ntype ErrType<T> = {\n readonly success: false;\n readonly error: ErrorStruct;\n} & (T extends object\n ? ShouldWrapObject<T> extends true\n ? { readonly result?: undefined }\n : { readonly [K in keyof T]?: undefined }\n : { readonly result?: undefined });\n\nexport type Result<T> = OkType<T> | ErrType<T>;\n\nexport function $ok<T>(result: T): Result<T> {\n if ($isPlainObj(result)) {\n const obj = result as Record<string, unknown>;\n if (Object.hasOwn(obj, \"success\") || Object.hasOwn(obj, \"error\")) {\n return { success: true, result } as Result<T>;\n }\n return { success: true, ...obj } as Result<T>;\n }\n return { success: true, result } as Result<T>;\n}\n\nexport function $err(err: ErrorStruct): Result<never> {\n return {\n success: false,\n error: { message: err.message, description: err.description },\n } as Result<never>;\n}\n\nexport function $fmtError(error: unknown): string {\n if (typeof error === \"string\") return error;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function $fmtResultErr(err: ErrorStruct | undefined): string {\n if (!err) return \"Unknown error\";\n return `${err.message} - ${err.description}`;\n}\n","import { $err, $fmtError, $ok, type Result } from \"./error.js\";\n\nexport const textEncoder = new TextEncoder();\nexport const textDecoder = new TextDecoder();\nconst strictUtf8Decoder = new TextDecoder(\"utf-8\", { fatal: true });\n\nexport const ENCODING = Object.freeze([\"base64\", \"base64url\", \"hex\", \"utf8\", \"latin1\"] as const);\nexport const CIPHER_ENCODING = Object.freeze([\"base64\", \"base64url\", \"hex\"] as const);\n\nexport type Encoding = (typeof ENCODING)[number];\nexport type CipherEncoding = (typeof CIPHER_ENCODING)[number];\n\nexport function $convertStrToBytes(\n data: string,\n inputEncoding: Encoding = \"utf8\",\n): Result<{ result: Uint8Array<ArrayBuffer> }> {\n if (typeof data !== \"string\") {\n return $err({\n message: \"strToBytes: Data must be a string\",\n description: `Expected a string value, received ${typeof data}`,\n });\n }\n if (!ENCODING.includes(inputEncoding)) {\n return $err({\n message: `strToBytes: Unsupported encoding: ${inputEncoding}`,\n description: \"Use base64, base64url, hex, utf8, or latin1\",\n });\n }\n\n try {\n const bytes = strToBytes[inputEncoding](data);\n return $ok({ result: bytes });\n } catch (error) {\n return $err({ message: \"strToBytes: Failed to convert data\", description: $fmtError(error) });\n }\n}\n\nexport function $convertBytesToStr(data: Uint8Array | ArrayBuffer, outputEncoding: Encoding = \"utf8\"): Result<string> {\n if (!(data instanceof ArrayBuffer || data instanceof Uint8Array)) {\n return $err({\n message: \"bytesToStr: Data must be an ArrayBuffer or Uint8Array\",\n description: `Expected binary data (ArrayBuffer or Uint8Array), received ${typeof data}`,\n });\n }\n if (!ENCODING.includes(outputEncoding)) {\n return $err({\n message: `bytesToStr: Unsupported encoding: ${outputEncoding}`,\n description: \"Use base64, base64url, hex, utf8, or latin1\",\n });\n }\n try {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\n const str = bytesToStr[outputEncoding](bytes);\n return $ok(str);\n } catch (error) {\n return $err({ message: \"bytesToStr: Failed to convert data\", description: $fmtError(error) });\n }\n}\n\nexport const strToBytes = {\n base64: $fromBase64,\n base64url: $fromBase64Url,\n hex: $fromHex,\n latin1: $fromLatin1,\n utf8: (data: string) => textEncoder.encode(data),\n} as const satisfies Record<Encoding, (data: string) => Uint8Array<ArrayBuffer>>;\n\nexport const bytesToStr = {\n base64: $toBase64,\n base64url: $toBase64Url,\n hex: $toHex,\n latin1: $toLatin1,\n utf8: (data: Uint8Array) => strictUtf8Decoder.decode(data),\n} as const satisfies Record<Encoding, (data: Uint8Array) => string>;\n\nexport function $toLatin1(bytes: Uint8Array): string {\n let out = \"\";\n const chunk = 1 << 15;\n for (let i = 0; i < bytes.length; i += chunk) {\n out += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n return out;\n}\n\nexport function $fromLatin1(data: string): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(data.length);\n for (let i = 0; i < data.length; i++) {\n const charCode = data.charCodeAt(i);\n if (charCode > 255) throw new Error(\"Invalid latin1 string\");\n out[i] = charCode;\n }\n return out;\n}\n\nexport function $toBase64(bytes: Uint8Array): string {\n return btoa($toLatin1(bytes));\n}\n\nconst BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}={2}|[A-Za-z0-9+/]{3}=)?$/;\n\nexport function $fromBase64(data: string): Uint8Array<ArrayBuffer> {\n if (!BASE64_REGEX.test(data)) throw new Error(\"Invalid base64 string\");\n return $fromLatin1(atob(data));\n}\n\nexport function $toBase64Url(bytes: Uint8Array): string {\n return $toBase64(bytes).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nconst BASE64URL_REGEX = /^[A-Za-z0-9_-]*={0,2}$/;\n\nexport function $fromBase64Url(data: string): Uint8Array<ArrayBuffer> {\n if (!BASE64URL_REGEX.test(data) || data.replace(/=+$/, \"\").length % 4 === 1) {\n throw new Error(\"Invalid base64url string\");\n }\n let base64 = data.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padLen = (4 - (base64.length % 4)) % 4;\n base64 += \"=\".repeat(padLen);\n return $fromBase64(base64);\n}\n\nconst HEX_TABLE = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, \"0\"));\n\nconst HEX_NIBBLE = new Uint8Array(256).fill(255);\nfor (let i = 48; i <= 57; i++) HEX_NIBBLE[i] = i - 48; // 0-9\nfor (let i = 65; i <= 70; i++) HEX_NIBBLE[i] = i - 55; // A-F\nfor (let i = 97; i <= 102; i++) HEX_NIBBLE[i] = i - 87; // a-f\n\nexport function $toHex(bytes: Uint8Array): string {\n const hex = new Array<string>(bytes.length);\n for (let i = 0; i < bytes.length; i++) {\n hex[i] = HEX_TABLE[bytes[i] as number] as string;\n }\n return hex.join(\"\");\n}\n\nexport function $fromHex(data: string): Uint8Array<ArrayBuffer> {\n const clean = data.startsWith(\"0x\") || data.startsWith(\"0X\") ? data.slice(2) : data;\n if (clean.length % 2 !== 0) throw new Error(\"Invalid hex string\");\n\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0, j = 0; i < clean.length; i += 2, j++) {\n const hiCode = clean.charCodeAt(i);\n const loCode = clean.charCodeAt(i + 1);\n if (hiCode > 255 || loCode > 255) throw new Error(\"Invalid hex string\");\n const hi = HEX_NIBBLE[hiCode] as number;\n const lo = HEX_NIBBLE[loCode] as number;\n if (hi === 255 || lo === 255) throw new Error(\"Invalid hex string\");\n out[j] = (hi << 4) | lo;\n }\n return out;\n}\n","import { $err, $fmtError, $ok, type Result } from \"./error.js\";\nimport { $isPlainObj, $isStr } from \"./validate.js\";\n\nclass ProtoTraversalLimitError extends Error {\n constructor(limit: number) {\n super(`Object graph exceeded prototype-scan limit (${limit} nodes)`);\n this.name = \"ProtoTraversalLimitError\";\n }\n}\n\nconst MAX_PROTO_SCAN_NODES = 100_000;\n\nfunction $hasProtoKey(obj: unknown): boolean {\n if (typeof obj !== \"object\" || obj === null) return false;\n\n const seen = new WeakSet<object>();\n const stack: unknown[] = [obj];\n let scannedNodes = 0;\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (typeof current !== \"object\" || current === null) continue;\n if (seen.has(current)) continue;\n\n seen.add(current);\n scannedNodes++;\n if (scannedNodes > MAX_PROTO_SCAN_NODES) {\n throw new ProtoTraversalLimitError(MAX_PROTO_SCAN_NODES);\n }\n\n if (Object.hasOwn(current, \"__proto__\")) return true;\n\n const currentObj = current as Record<string, unknown>;\n if (\n Object.hasOwn(currentObj, \"constructor\") &&\n typeof currentObj.constructor === \"object\" &&\n currentObj.constructor !== null &&\n Object.hasOwn(currentObj.constructor as object, \"prototype\") &&\n typeof (currentObj.constructor as Record<string, unknown>).prototype === \"object\" &&\n (currentObj.constructor as Record<string, unknown>).prototype !== null\n ) {\n return true;\n }\n\n for (const val of Object.values(currentObj)) {\n if (typeof val === \"object\" && val !== null) {\n stack.push(val);\n }\n }\n }\n\n return false;\n}\n\nexport function $stringifyObj<T extends object = Record<string, unknown>>(obj: T): Result<string> {\n if (!$isPlainObj(obj))\n return $err({\n message: \"stringifyObj: Input must be a plain object\",\n description: \"Only plain objects ({...}) are accepted, not arrays, class instances, or built-ins\",\n });\n try {\n return $ok(JSON.stringify(obj));\n } catch (error) {\n return $err({ message: \"stringifyObj: Failed to stringify object\", description: $fmtError(error) });\n }\n}\n\nexport function $parseToObj<T extends object = Record<string, unknown>>(str: string): Result<{ result: T }> {\n if (!$isStr(str))\n return $err({\n message: \"parseToObj: Input must be a non-empty string\",\n description: \"Expected a non-empty JSON string to parse\",\n });\n\n try {\n const obj = JSON.parse(str);\n\n if (!$isPlainObj(obj)) {\n return $err({\n message: \"parseToObj: Parsed data is not a plain object\",\n description: \"JSON parsed successfully but the result is not a plain object (e.g. array, string, number)\",\n });\n }\n\n if ($hasProtoKey(obj)) {\n return $err({\n message: \"parseToObj: Input contains a prototype pollution vector\",\n description: \"Objects with __proto__ or constructor.prototype keys are rejected\",\n });\n }\n\n return $ok({ result: obj as T });\n } catch (error) {\n if (error instanceof ProtoTraversalLimitError) {\n return $err({\n message: \"parseToObj: Input object is too deeply nested to validate safely\",\n description: error.message,\n });\n }\n return $err({ message: \"parseToObj: Failed to parse JSON\", description: $fmtError(error) });\n }\n}\n","export { CIPHER_ENCODING, ENCODING } from \"@internal/helpers\";\n\nexport const GCM_TAG_BYTES = 16;\nexport const GCM_IV_LENGTH = 12;\n\nexport const MAX_PBKDF2_ITERATIONS = 10_000_000;\nexport const MAX_PBKDF2_KEY_LENGTH = 1024;\nexport const MAX_PBKDF2_SALT_LENGTH = 1024;\n\nexport const DIGEST_ALGORITHMS = Object.freeze({\n sha256: { node: \"sha256\", web: \"SHA-256\" },\n sha384: { node: \"sha384\", web: \"SHA-384\" },\n sha512: { node: \"sha512\", web: \"SHA-512\" },\n} as const);\n\nexport const ENCRYPTION_ALGORITHMS = Object.freeze({\n aes256gcm: { keyBytes: 32, node: \"aes-256-gcm\", web: \"AES-GCM\" },\n aes192gcm: { keyBytes: 24, node: \"aes-192-gcm\", web: \"AES-GCM\" },\n aes128gcm: { keyBytes: 16, node: \"aes-128-gcm\", web: \"AES-GCM\" },\n} as const);\n","import { $err, $isIntIn, $isPlainObj, $isStr, $ok, type Result } from \"@internal/helpers\";\nimport {\n CIPHER_ENCODING,\n DIGEST_ALGORITHMS,\n ENCRYPTION_ALGORITHMS,\n MAX_PBKDF2_ITERATIONS,\n MAX_PBKDF2_KEY_LENGTH,\n MAX_PBKDF2_SALT_LENGTH,\n} from \"./consts.js\";\nimport type {\n CreateSecretKeyOptions,\n HashPasswordOptions,\n ValidatedHashOptions,\n ValidatedKdfOptions,\n ValidatedVerifyOptions,\n VerifyPasswordOptions,\n} from \"./types.js\";\n\nexport function $isObj(x: unknown): x is Record<string, unknown> {\n return typeof x === \"object\" && x !== null;\n}\n\nconst expectedKeys = new Set([\"platform\", \"digest\", \"algorithm\", \"key\", \"injected\"]);\n\nexport function $validateSecretKeyBase(\n x: unknown,\n platform: \"node\" | \"web\",\n): {\n obj: Record<string, unknown>;\n algorithm: (typeof ENCRYPTION_ALGORITHMS)[keyof typeof ENCRYPTION_ALGORITHMS];\n} | null {\n if (!$isObj(x) || (platform !== \"node\" && platform !== \"web\") || x.platform !== platform) return null;\n\n const keys = Object.keys(x);\n if (keys.length !== expectedKeys.size) return null;\n for (const key of keys) if (!expectedKeys.has(key)) return null;\n\n if (\n typeof x.digest !== \"string\" ||\n !(x.digest in DIGEST_ALGORITHMS) ||\n typeof x.algorithm !== \"string\" ||\n !(x.algorithm in ENCRYPTION_ALGORITHMS) ||\n !$isObj(x.key) ||\n x.key.type !== \"secret\"\n ) {\n return null;\n }\n\n const algorithm = ENCRYPTION_ALGORITHMS[x.algorithm as keyof typeof ENCRYPTION_ALGORITHMS];\n\n if (\n !$isObj(x.injected) ||\n x.injected.keyBytes !== algorithm.keyBytes ||\n x.injected.node !== algorithm.node ||\n x.injected.web !== algorithm.web\n ) {\n return null;\n }\n\n return { obj: x, algorithm };\n}\n\n/** Matches the `\"iv.cipher.tag.\"` encrypted payload format. */\nexport const ENCRYPTED_REGEX =\n /^([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\\.([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\\.([A-Za-z0-9+/_-][A-Za-z0-9+/=_-]*)\\.$/;\n\n/**\n * Structural check only — validates the dot-separated `\"iv.cipher.tag.\"` format\n * but does NOT verify that individual segments contain valid base64, base64url, or hex encoding.\n */\nexport function matchEncryptedPattern(data: string): boolean {\n return typeof data === \"string\" && ENCRYPTED_REGEX.test(data);\n}\n\nexport function $validateCreateSecretKeyOptions(\n secret: string,\n options: CreateSecretKeyOptions,\n prefix: string,\n): Result<ValidatedKdfOptions> {\n if (!$isStr(secret, 8)) {\n return $err({\n message: `${prefix} createSecretKey: Secret must be at least 8 characters`,\n description: \"Use a high-entropy string of at least 8 characters\",\n });\n }\n\n if (!$isPlainObj<CreateSecretKeyOptions>(options)) {\n return $err({\n message: `${prefix} createSecretKey: Options must be a plain object`,\n description: 'Pass an object like { algorithm: \"aes256gcm\" }',\n });\n }\n\n const algorithm = options.algorithm ?? \"aes256gcm\";\n if (!(algorithm in ENCRYPTION_ALGORITHMS)) {\n return $err({\n message: `${prefix} createSecretKey: Unsupported algorithm: ${algorithm}`,\n description: `Supported algorithms are: ${Object.keys(ENCRYPTION_ALGORITHMS).join(\", \")}`,\n });\n }\n\n const digest = options.digest ?? \"sha256\";\n if (!(digest in DIGEST_ALGORITHMS)) {\n return $err({\n message: `${prefix} createSecretKey: Unsupported digest: ${digest}`,\n description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(\", \")}`,\n });\n }\n\n const salt = options.salt ?? \"cipher-kit\";\n if (!$isStr(salt, 8)) {\n return $err({\n message: `${prefix} createSecretKey: Salt must be at least 8 characters`,\n description: \"Provide a salt string with at least 8 characters\",\n });\n }\n\n const info = options.info ?? \"cipher-kit\";\n if (!$isStr(info)) {\n return $err({\n message: `${prefix} createSecretKey: Info must be a non-empty string`,\n description: \"Received empty or non-string value\",\n });\n }\n\n return $ok({\n algorithm,\n digest,\n salt,\n info,\n encryptAlgo: ENCRYPTION_ALGORITHMS[algorithm],\n digestAlgo: DIGEST_ALGORITHMS[digest],\n });\n}\n\nexport function $validateHashPasswordOptions(\n password: string,\n options: HashPasswordOptions,\n prefix: string,\n): Result<ValidatedHashOptions> {\n if (!$isStr(password)) {\n return $err({\n message: `${prefix} hashPassword: Password must be a non-empty string`,\n description: \"Received empty or non-string value\",\n });\n }\n\n if (!$isPlainObj<HashPasswordOptions>(options)) {\n return $err({\n message: `${prefix} hashPassword: Options must be a plain object`,\n description: \"Pass an object like { iterations: 320000 }\",\n });\n }\n\n const digest = options.digest ?? \"sha512\";\n if (!(digest in DIGEST_ALGORITHMS)) {\n return $err({\n message: `${prefix} hashPassword: Unsupported digest: ${digest}`,\n description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(\", \")}`,\n });\n }\n\n const outputEncoding = options.outputEncoding ?? \"base64url\";\n if (!CIPHER_ENCODING.includes(outputEncoding)) {\n return $err({\n message: `${prefix} hashPassword: Unsupported output encoding: ${outputEncoding}`,\n description: \"Use base64, base64url, or hex\",\n });\n }\n\n const saltLength = options.saltLength ?? 16;\n if (!$isIntIn(saltLength, 8, MAX_PBKDF2_SALT_LENGTH)) {\n return $err({\n message: `${prefix} hashPassword: Salt length must be at least 8 bytes`,\n description: `Must be an integer between 8 and ${MAX_PBKDF2_SALT_LENGTH} (recommended 16 or more)`,\n });\n }\n\n const iterations = options.iterations ?? 320_000;\n if (!$isIntIn(iterations, 100_000, MAX_PBKDF2_ITERATIONS)) {\n return $err({\n message: `${prefix} hashPassword: Iterations must be at least 100,000`,\n description: `Must be an integer between 100,000 and ${MAX_PBKDF2_ITERATIONS} (recommended 320,000 or more)`,\n });\n }\n\n const keyLength = options.keyLength ?? 64;\n if (!$isIntIn(keyLength, 16, MAX_PBKDF2_KEY_LENGTH)) {\n return $err({\n message: `${prefix} hashPassword: Key length must be at least 16 bytes`,\n description: `Must be an integer between 16 and ${MAX_PBKDF2_KEY_LENGTH} (recommended 64 or more)`,\n });\n }\n\n return $ok({\n digest,\n digestAlgo: DIGEST_ALGORITHMS[digest],\n outputEncoding,\n saltLength,\n iterations,\n keyLength,\n });\n}\n\nfunction $maxEncodedLength(byteLength: number, encoding: (typeof CIPHER_ENCODING)[number]): number {\n if (encoding === \"hex\") return byteLength * 2;\n return Math.ceil(byteLength / 3) * 4;\n}\n\nexport function $validateVerifyPasswordOptions(\n password: string,\n hashedPassword: string,\n salt: string,\n options: VerifyPasswordOptions,\n prefix: string,\n): Result<ValidatedVerifyOptions> {\n if (!$isStr(password)) {\n return $err({\n message: `${prefix} verifyPassword: Password must be a non-empty string`,\n description: \"Received empty or non-string value\",\n });\n }\n\n if (!$isStr(hashedPassword)) {\n return $err({\n message: `${prefix} verifyPassword: Hashed password must be a non-empty string`,\n description: \"Pass the hash string returned by hashPassword()\",\n });\n }\n\n if (!$isStr(salt)) {\n return $err({\n message: `${prefix} verifyPassword: Salt must be a non-empty string`,\n description: \"Pass the salt string returned by hashPassword()\",\n });\n }\n\n if (!$isPlainObj<VerifyPasswordOptions>(options)) {\n return $err({\n message: `${prefix} verifyPassword: Options must be a plain object`,\n description: \"Pass an object matching the options used for hashPassword()\",\n });\n }\n\n const digest = options.digest ?? \"sha512\";\n if (!(digest in DIGEST_ALGORITHMS)) {\n return $err({\n message: `${prefix} verifyPassword: Unsupported digest: ${digest}`,\n description: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(\", \")}`,\n });\n }\n\n const inputEncoding = options.inputEncoding ?? \"base64url\";\n if (!CIPHER_ENCODING.includes(inputEncoding)) {\n return $err({\n message: `${prefix} verifyPassword: Unsupported input encoding: ${inputEncoding}`,\n description: \"Use base64, base64url, or hex\",\n });\n }\n\n const iterations = options.iterations ?? 320_000;\n if (!$isIntIn(iterations, 100_000, MAX_PBKDF2_ITERATIONS)) {\n return $err({\n message: `${prefix} verifyPassword: Iterations must be at least 100,000`,\n description: `Must be an integer between 100,000 and ${MAX_PBKDF2_ITERATIONS}`,\n });\n }\n\n const keyLength = options.keyLength ?? 64;\n if (!$isIntIn(keyLength, 16, MAX_PBKDF2_KEY_LENGTH)) {\n return $err({\n message: `${prefix} verifyPassword: Key length must be at least 16 bytes`,\n description: `Must be an integer between 16 and ${MAX_PBKDF2_KEY_LENGTH}`,\n });\n }\n\n const maxHashLen = $maxEncodedLength(keyLength, inputEncoding);\n if (hashedPassword.length > maxHashLen) {\n return $err({\n message: `${prefix} verifyPassword: Hashed password exceeds maximum encoded length`,\n description: `Expected at most ${maxHashLen} characters for ${keyLength}-byte key with ${inputEncoding} encoding`,\n });\n }\n\n const maxSaltLen = $maxEncodedLength(MAX_PBKDF2_SALT_LENGTH, inputEncoding);\n if (salt.length > maxSaltLen) {\n return $err({\n message: `${prefix} verifyPassword: Salt exceeds maximum encoded length`,\n description: `Expected at most ${maxSaltLen} characters for ${inputEncoding} encoding`,\n });\n }\n\n return $ok({\n digest,\n digestAlgo: DIGEST_ALGORITHMS[digest],\n inputEncoding,\n iterations,\n keyLength,\n });\n}\n","import { $fmtResultErr, $parseToObj, $stringifyObj, type Result } from \"@internal/helpers\";\n\n/**\n * Serializes a plain object to JSON (non-throwing).\n *\n * @returns `Result<string>` with the JSON string or error.\n * @see {@link stringifyObj} For full parameter/behavior docs.\n */\nexport function tryStringifyObj<T extends object = Record<string, unknown>>(obj: T): Result<string> {\n return $stringifyObj(obj);\n}\n\n/**\n * Serializes a plain object to JSON.\n *\n * @remarks\n * Only plain objects (POJOs) are accepted; class instances, Maps, Sets, etc. are rejected.\n *\n * @param obj - The object to stringify.\n * @returns JSON string representation of the object.\n * @throws {Error} If `obj` is not a plain object or serialization fails.\n *\n * @example\n * ```ts\n * const json = stringifyObj({ a: 1 }); // '{\"a\":1}'\n * ```\n *\n * @see {@link tryStringifyObj} Non-throwing variant returning `Result<string>`.\n */\nexport function stringifyObj<T extends object = Record<string, unknown>>(obj: T): string {\n const { result, error } = $stringifyObj(obj);\n if (error) throw new Error($fmtResultErr(error));\n return result;\n}\n\n/**\n * Parses a JSON string to a plain object (non-throwing).\n *\n * @returns `Result<{ result: T }>` with the parsed object or error.\n * @see {@link parseToObj} For full parameter/behavior docs.\n */\nexport function tryParseToObj<T extends object = Record<string, unknown>>(str: string): Result<{ result: T }> {\n return $parseToObj<T>(str);\n}\n\n/**\n * Parses a JSON string to a plain object.\n *\n * @param str - The JSON string to parse.\n * @returns The parsed plain object.\n * @throws {Error} If the string can't be parsed or doesn't represent a plain object.\n *\n * @example\n * ```ts\n * const obj = parseToObj<{ a: number }>('{\"a\":1}'); // obj.a === 1\n * ```\n *\n * @see {@link tryParseToObj} Non-throwing variant returning `Result<{ result: T }>`.\n */\nexport function parseToObj<T extends object = Record<string, unknown>>(str: string): T {\n const { result, error } = $parseToObj<T>(str);\n if (error) throw new Error($fmtResultErr(error));\n return result;\n}\n"]}
|