cipher-kit 2.0.0-beta.3 → 2.0.0-beta.4

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.
Files changed (45) hide show
  1. package/dist/{chunk-BNQERV4S.js → chunk-LHB5NXYW.js} +71 -84
  2. package/dist/chunk-LHB5NXYW.js.map +1 -0
  3. package/dist/{chunk-6GBH7YTP.js → chunk-N5T4PNG7.js} +67 -81
  4. package/dist/chunk-N5T4PNG7.js.map +1 -0
  5. package/dist/{chunk-UHP3PPXP.cjs → chunk-OL2AIXWK.cjs} +150 -165
  6. package/dist/chunk-OL2AIXWK.cjs.map +1 -0
  7. package/dist/{chunk-ZJ32WGAA.cjs → chunk-UIV6DG54.cjs} +15 -12
  8. package/dist/chunk-UIV6DG54.cjs.map +1 -0
  9. package/dist/{chunk-NKLNWTQA.cjs → chunk-XIWV7XVI.cjs} +159 -173
  10. package/dist/chunk-XIWV7XVI.cjs.map +1 -0
  11. package/dist/{chunk-YPYDYYV2.js → chunk-YMNOTRET.js} +13 -11
  12. package/dist/chunk-YMNOTRET.js.map +1 -0
  13. package/dist/export-D1Vh79Qw.d.ts +417 -0
  14. package/dist/export-DGrELdz_.d.ts +416 -0
  15. package/dist/export-DXRl-ncG.d.cts +417 -0
  16. package/dist/export-Gd8hafl6.d.cts +416 -0
  17. package/dist/index.cjs +14 -22
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +52 -4
  20. package/dist/index.d.ts +52 -4
  21. package/dist/index.js +9 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/node.cjs +34 -42
  24. package/dist/node.d.cts +2 -2
  25. package/dist/node.d.ts +2 -2
  26. package/dist/node.js +2 -2
  27. package/dist/validate-Cb7IOrPo.d.cts +373 -0
  28. package/dist/validate-Cb7IOrPo.d.ts +373 -0
  29. package/dist/web-api.cjs +34 -42
  30. package/dist/web-api.d.cts +2 -2
  31. package/dist/web-api.d.ts +2 -2
  32. package/dist/web-api.js +2 -2
  33. package/package.json +1 -1
  34. package/dist/chunk-6GBH7YTP.js.map +0 -1
  35. package/dist/chunk-BNQERV4S.js.map +0 -1
  36. package/dist/chunk-NKLNWTQA.cjs.map +0 -1
  37. package/dist/chunk-UHP3PPXP.cjs.map +0 -1
  38. package/dist/chunk-YPYDYYV2.js.map +0 -1
  39. package/dist/chunk-ZJ32WGAA.cjs.map +0 -1
  40. package/dist/export--ndIQ3j3.d.cts +0 -271
  41. package/dist/export-C2M5UPLX.d.cts +0 -270
  42. package/dist/export-CPUbAFZA.d.ts +0 -271
  43. package/dist/export-v9ULdDL0.d.ts +0 -270
  44. package/dist/validate-CULVlPck.d.cts +0 -157
  45. package/dist/validate-CULVlPck.d.ts +0 -157
@@ -1,4 +1,4 @@
1
- import { __export, $fmtResultErr, $ok, $err, $fmtError, $isStr, ENCRYPTION_ALGORITHMS, DIGEST_ALGORITHMS, ENCODINGS, $isSecretKey, matchPattern, $stringifyObj, $parseToObj } from './chunk-YPYDYYV2.js';
1
+ import { __export, $isSecretKey, $fmtResultErr, $ok, $err, $fmtError, title, $isStr, ENCRYPTION_ALGORITHMS, DIGEST_ALGORITHMS, CIPHER_ENCODING, matchPattern, $stringifyObj, $parseToObj, ENCODING } from './chunk-YMNOTRET.js';
2
2
 
3
3
  // src/web/kit.ts
4
4
  var kit_exports = {};
@@ -13,8 +13,8 @@ __export(kit_exports, {
13
13
  encryptObj: () => encryptObj,
14
14
  generateUuid: () => generateUuid,
15
15
  hash: () => hash,
16
- hashObj: () => hashObj,
17
16
  hashPassword: () => hashPassword,
17
+ isWebSecretKey: () => isWebSecretKey,
18
18
  tryConvertBytesToStr: () => tryConvertBytesToStr,
19
19
  tryConvertEncoding: () => tryConvertEncoding,
20
20
  tryConvertStrToBytes: () => tryConvertStrToBytes,
@@ -25,7 +25,6 @@ __export(kit_exports, {
25
25
  tryEncryptObj: () => tryEncryptObj,
26
26
  tryGenerateUuid: () => tryGenerateUuid,
27
27
  tryHash: () => tryHash,
28
- tryHashObj: () => tryHashObj,
29
28
  tryHashPassword: () => tryHashPassword,
30
29
  verifyPassword: () => verifyPassword
31
30
  });
@@ -40,7 +39,7 @@ function $convertStrToBytes(data, inputEncoding = "utf8") {
40
39
  desc: "Data must be a non-empty string"
41
40
  });
42
41
  }
43
- if (!ENCODINGS.includes(inputEncoding)) {
42
+ if (!ENCODING.includes(inputEncoding)) {
44
43
  return $err({
45
44
  msg: `Crypto Web API - String to Bytes: Unsupported encoding: ${inputEncoding}`,
46
45
  desc: "Use base64, base64url, hex, utf8, or latin1"
@@ -60,7 +59,7 @@ function $convertBytesToStr(data, outputEncoding = "utf8") {
60
59
  desc: "Data must be an ArrayBuffer or Uint8Array"
61
60
  });
62
61
  }
63
- if (!ENCODINGS.includes(outputEncoding)) {
62
+ if (!ENCODING.includes(outputEncoding)) {
64
63
  return $err({
65
64
  msg: `Crypto Web API - Bytes to String: Unsupported encoding: ${outputEncoding}`,
66
65
  desc: "Use base64, base64url, hex, utf8, or latin1"
@@ -81,7 +80,7 @@ function $convertEncoding(data, from, to) {
81
80
  desc: "Data must be a non-empty string"
82
81
  });
83
82
  }
84
- if (!ENCODINGS.includes(from) || !ENCODINGS.includes(to)) {
83
+ if (!ENCODING.includes(from) || !ENCODING.includes(to)) {
85
84
  return $err({
86
85
  msg: `Crypto Web API - Convert Format: Unsupported encoding: from ${from} to ${to}`,
87
86
  desc: "Use base64, base64url, hex, utf8, or latin1"
@@ -159,38 +158,38 @@ function $generateUuid() {
159
158
  try {
160
159
  return $ok(crypto.randomUUID());
161
160
  } catch (error) {
162
- return $err({ msg: "Crypto Web API - UUID Generation: Failed to generate UUID", desc: $fmtError(error) });
161
+ return $err({ msg: `${title("web", "UUID Generation")}: Failed to generate UUID`, desc: $fmtError(error) });
163
162
  }
164
163
  }
165
164
  async function $createSecretKey(secret, options = {}) {
166
165
  if (!$isStr(secret)) {
167
- return $err({ msg: "Crypto Web API - Key Generation: Empty Secret", desc: "Secret must be a non-empty string" });
166
+ return $err({ msg: `${title("web", "Key Generation")}: Empty Secret`, desc: "Secret must be a non-empty string" });
168
167
  }
169
168
  const algorithm = options.algorithm ?? "aes256gcm";
170
169
  if (!(algorithm in ENCRYPTION_ALGORITHMS)) {
171
170
  return $err({
172
- msg: `Crypto NodeJS API - Key Generation: Unsupported algorithm: ${algorithm}`,
171
+ msg: `${title("web", "Key Generation")}: Unsupported algorithm: ${algorithm}`,
173
172
  desc: `Supported algorithms are: ${Object.keys(ENCRYPTION_ALGORITHMS).join(", ")}`
174
173
  });
175
174
  }
176
175
  const digest = options.digest ?? "sha256";
177
176
  if (!(digest in DIGEST_ALGORITHMS)) {
178
177
  return $err({
179
- msg: `Crypto NodeJS API - Key Generation: Unsupported digest: ${digest}`,
178
+ msg: `${title("web", "Key Generation")}: Unsupported digest: ${digest}`,
180
179
  desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
181
180
  });
182
181
  }
183
182
  const salt = options.salt ?? "cipher-kit-salt";
184
183
  if (!$isStr(salt, 8)) {
185
184
  return $err({
186
- msg: "Crypto NodeJS API - Key Generation: Weak salt",
185
+ msg: `${title("web", "Key Generation")}: Weak salt`,
187
186
  desc: "Salt must be a non-empty string with at least 8 characters"
188
187
  });
189
188
  }
190
189
  const info = options.info ?? "cipher-kit";
191
190
  if (!$isStr(info)) {
192
191
  return $err({
193
- msg: "Crypto NodeJS API - Key Generation: Invalid info",
192
+ msg: `${title("web", "Key Generation")}: Invalid info`,
194
193
  desc: "Info must be a non-empty string"
195
194
  });
196
195
  }
@@ -221,7 +220,7 @@ async function $createSecretKey(secret, options = {}) {
221
220
  return $ok({ result: secretKey });
222
221
  } catch (error) {
223
222
  return $err({
224
- msg: "Crypto Web API - Key Generation: Failed to create secret key",
223
+ msg: `${title("web", "Key Generation")}: Failed to create secret key`,
225
224
  desc: $fmtError(error)
226
225
  });
227
226
  }
@@ -229,26 +228,25 @@ async function $createSecretKey(secret, options = {}) {
229
228
  async function $encrypt(data, secretKey, options = {}) {
230
229
  if (!$isStr(data)) {
231
230
  return $err({
232
- msg: "Crypto Web API - Encryption: Empty data for encryption",
231
+ msg: `${title("web", "Encryption")}: Empty data for encryption`,
233
232
  desc: "Data must be a non-empty string"
234
233
  });
235
234
  }
236
- const inputEncoding = options.inputEncoding ?? "utf8";
237
- const outputEncoding = options.outputEncoding ?? "base64url";
238
- if (!ENCODINGS.includes(inputEncoding) || !ENCODINGS.includes(outputEncoding)) {
235
+ const encoding = options.encoding ?? "base64url";
236
+ if (!CIPHER_ENCODING.includes(encoding)) {
239
237
  return $err({
240
- msg: `Crypto Web API - Encryption: Unsupported encoding: input ${inputEncoding} or output ${outputEncoding}`,
241
- desc: "Use base64, base64url, hex, utf8, or latin1"
238
+ msg: `${title("web", "Encryption")}: Unsupported output encoding: ${encoding}`,
239
+ desc: "Use base64, base64url, or hex"
242
240
  });
243
241
  }
244
242
  const injectedKey = $isSecretKey(secretKey, "web");
245
243
  if (!injectedKey) {
246
244
  return $err({
247
- msg: "Crypto Web API - Encryption: Invalid Secret Key",
245
+ msg: `${title("web", "Encryption")}: Invalid Secret Key`,
248
246
  desc: "Expected a Web SecretKey"
249
247
  });
250
248
  }
251
- const { result, error } = $convertStrToBytes(data, inputEncoding);
249
+ const { result, error } = $convertStrToBytes(data, "utf8");
252
250
  if (error) return $err(error);
253
251
  try {
254
252
  const iv = crypto.getRandomValues(new Uint8Array(injectedKey.injected.ivLength));
@@ -257,54 +255,53 @@ async function $encrypt(data, secretKey, options = {}) {
257
255
  injectedKey.key,
258
256
  result
259
257
  );
260
- const ivStr = $convertBytesToStr(iv, outputEncoding);
261
- const cipherStr = $convertBytesToStr(cipherWithTag, outputEncoding);
258
+ const ivStr = $convertBytesToStr(iv, encoding);
259
+ const cipherStr = $convertBytesToStr(cipherWithTag, encoding);
262
260
  if (ivStr.error || cipherStr.error) {
263
261
  return $err({
264
- msg: "Crypto Web API - Encryption: Failed to convert IV or encrypted data",
265
- desc: `Conversion error: ${ivStr.error || cipherStr.error}`
262
+ msg: `${title("web", "Encryption")}: Failed to convert IV or encrypted data`,
263
+ desc: `Conversion error: ${$fmtResultErr(ivStr.error || cipherStr.error)}`
266
264
  });
267
265
  }
268
266
  return $ok(`${ivStr.result}.${cipherStr.result}.`);
269
267
  } catch (error2) {
270
- return $err({ msg: "Crypto Web API - Encryption: Failed to encrypt data", desc: $fmtError(error2) });
268
+ return $err({ msg: `${title("web", "Encryption")}: Failed to encrypt data`, desc: $fmtError(error2) });
271
269
  }
272
270
  }
273
271
  async function $decrypt(encrypted, secretKey, options = {}) {
274
272
  if (matchPattern(encrypted, "web") === false) {
275
273
  return $err({
276
- msg: "Crypto Web API - Decryption: Invalid encrypted data format",
274
+ msg: `${title("web", "Decryption")}: Invalid encrypted data format`,
277
275
  desc: 'Encrypted data must be in the format "iv.cipherWithTag."'
278
276
  });
279
277
  }
280
- const inputEncoding = options.inputEncoding ?? "base64url";
281
- const outputEncoding = options.outputEncoding ?? "utf8";
282
- if (!ENCODINGS.includes(inputEncoding) || !ENCODINGS.includes(outputEncoding)) {
278
+ const encoding = options.encoding ?? "base64url";
279
+ if (!CIPHER_ENCODING.includes(encoding)) {
283
280
  return $err({
284
- msg: `Crypto Web API - Decryption: Unsupported encoding: input ${inputEncoding} or output ${outputEncoding}`,
285
- desc: "Use base64, base64url, hex, utf8, or latin1"
281
+ msg: `${title("web", "Decryption")}: Unsupported input encoding: ${encoding}`,
282
+ desc: "Use base64, base64url, or hex"
286
283
  });
287
284
  }
288
285
  const [iv, encryptedWithTag] = encrypted.split(".", 3);
289
286
  if (!$isStr(iv) || !$isStr(encryptedWithTag)) {
290
287
  return $err({
291
- msg: "Crypto Web API - Decryption: Invalid encrypted data",
288
+ msg: `${title("web", "Decryption")}: Invalid encrypted data`,
292
289
  desc: "Encrypted data must contain valid IV, encrypted and tag components"
293
290
  });
294
291
  }
295
292
  const injectedKey = $isSecretKey(secretKey, "web");
296
293
  if (!injectedKey) {
297
294
  return $err({
298
- msg: "Crypto Web API - Decryption: Invalid Secret Key",
295
+ msg: `${title("web", "Decryption")}: Invalid Secret Key`,
299
296
  desc: "Expected a Web SecretKey"
300
297
  });
301
298
  }
302
- const ivBytes = $convertStrToBytes(iv, inputEncoding);
303
- const cipherWithTagBytes = $convertStrToBytes(encryptedWithTag, inputEncoding);
299
+ const ivBytes = $convertStrToBytes(iv, encoding);
300
+ const cipherWithTagBytes = $convertStrToBytes(encryptedWithTag, encoding);
304
301
  if (ivBytes.error || cipherWithTagBytes.error) {
305
302
  return $err({
306
- msg: "Crypto Web API - Decryption: Failed to convert IV or encrypted data",
307
- desc: `Conversion error: ${ivBytes.error || cipherWithTagBytes.error}`
303
+ msg: `${title("web", "Decryption")}: Failed to convert IV or encrypted data`,
304
+ desc: `Conversion error: ${$fmtResultErr(ivBytes.error || cipherWithTagBytes.error)}`
308
305
  });
309
306
  }
310
307
  try {
@@ -315,7 +312,7 @@ async function $decrypt(encrypted, secretKey, options = {}) {
315
312
  );
316
313
  return $convertBytesToStr(decrypted, "utf8");
317
314
  } catch (error) {
318
- return $err({ msg: "Crypto Web API - Decryption: Failed to decrypt data", desc: $fmtError(error) });
315
+ return $err({ msg: `${title("web", "Decryption")}: Failed to decrypt data`, desc: $fmtError(error) });
319
316
  }
320
317
  }
321
318
  async function $encryptObj(data, secretKey, options = {}) {
@@ -330,78 +327,72 @@ async function $decryptObj(encrypted, secretKey, options = {}) {
330
327
  }
331
328
  async function $hash(data, options = {}) {
332
329
  if (!$isStr(data)) {
333
- return $err({ msg: "Crypto Web API - Hashing: Empty data for hashing", desc: "Data must be a non-empty string" });
330
+ return $err({ msg: `${title("web", "Hashing")}: Empty data for hashing`, desc: "Data must be a non-empty string" });
334
331
  }
335
- const inputEncoding = options.inputEncoding ?? "utf8";
336
- const outputEncoding = options.outputEncoding ?? "base64url";
337
- if (!ENCODINGS.includes(inputEncoding) || !ENCODINGS.includes(outputEncoding)) {
332
+ const encoding = options.encoding ?? "base64url";
333
+ if (!CIPHER_ENCODING.includes(encoding)) {
338
334
  return $err({
339
- msg: `Crypto Web API - Hashing: Unsupported input encoding: ${inputEncoding} or output encoding: ${outputEncoding}`,
340
- desc: "Use base64, base64url, hex, utf8, or latin1"
335
+ msg: `${title("web", "Hashing")}: Unsupported output encoding: ${encoding}`,
336
+ desc: "Use base64, base64url, or hex"
341
337
  });
342
338
  }
343
339
  const digest = options.digest ?? "sha256";
344
340
  if (!(digest in DIGEST_ALGORITHMS)) {
345
341
  return $err({
346
- msg: `Crypto Web API - Hashing: Unsupported digest: ${digest}`,
342
+ msg: `${title("web", "Hashing")}: Unsupported digest: ${digest}`,
347
343
  desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
348
344
  });
349
345
  }
350
346
  const digestAlgo = DIGEST_ALGORITHMS[digest];
351
- const { result, error } = $convertStrToBytes(data, inputEncoding);
347
+ const { result, error } = $convertStrToBytes(data, "utf8");
352
348
  if (error) return $err(error);
353
349
  try {
354
350
  const hashed = await crypto.subtle.digest(digestAlgo.web, result);
355
- return $convertBytesToStr(hashed, outputEncoding);
351
+ return $convertBytesToStr(hashed, encoding);
356
352
  } catch (error2) {
357
- return $err({ msg: "Crypto Web API - Hashing: Failed to hash data", desc: $fmtError(error2) });
353
+ return $err({ msg: `${title("web", "Hashing")}: Failed to hash data`, desc: $fmtError(error2) });
358
354
  }
359
355
  }
360
- async function $hashObj(data, options = {}) {
361
- const { result, error } = $stringifyObj(data);
362
- if (error) return $err(error);
363
- return await $hash(result, options);
364
- }
365
356
  async function $hashPassword(password, options = {}) {
366
357
  if (!$isStr(password)) {
367
358
  return $err({
368
- msg: "Crypto Web API - Password Hashing: Empty password",
359
+ msg: `${title("web", "Password Hashing")}: Empty password`,
369
360
  desc: "Password must be a non-empty string"
370
361
  });
371
362
  }
372
363
  const digest = options.digest ?? "sha512";
373
364
  if (!(digest in DIGEST_ALGORITHMS)) {
374
365
  return $err({
375
- msg: `Crypto Web API - Password Hashing: Unsupported digest: ${digest}`,
366
+ msg: `${title("web", "Password Hashing")}: Unsupported digest: ${digest}`,
376
367
  desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(", ")}`
377
368
  });
378
369
  }
379
370
  const digestAlgo = DIGEST_ALGORITHMS[digest];
380
- const outputEncoding = options.outputEncoding ?? "base64url";
381
- if (!ENCODINGS.includes(outputEncoding)) {
371
+ const encoding = options.encoding ?? "base64url";
372
+ if (!CIPHER_ENCODING.includes(encoding)) {
382
373
  return $err({
383
- msg: `Crypto Web API - Password Hashing: Unsupported output encoding: ${outputEncoding}`,
384
- desc: "Use base64, base64url, hex, utf8, or latin1"
374
+ msg: `${title("web", "Password Hashing")}: Unsupported output encoding: ${encoding}`,
375
+ desc: "Use base64, base64url, or hex"
385
376
  });
386
377
  }
387
378
  const saltLength = options.saltLength ?? 16;
388
379
  if (typeof saltLength !== "number" || saltLength < 8) {
389
380
  return $err({
390
- msg: "Crypto Web API - Password Hashing: Weak salt length",
381
+ msg: `${title("web", "Password Hashing")}: Weak salt length`,
391
382
  desc: "Salt length must be a number and at least 8 bytes (recommended 16)"
392
383
  });
393
384
  }
394
385
  const iterations = options.iterations ?? 32e4;
395
386
  if (typeof iterations !== "number" || iterations < 1e3) {
396
387
  return $err({
397
- msg: "Crypto Web API - Password Hashing: Weak iteration count",
388
+ msg: `${title("web", "Password Hashing")}: Weak iteration count`,
398
389
  desc: "Iterations must be a number and at least 1000 (recommended 320,000 or more)"
399
390
  });
400
391
  }
401
392
  const keyLength = options.keyLength ?? 64;
402
393
  if (typeof keyLength !== "number" || keyLength < 16) {
403
394
  return $err({
404
- msg: "Crypto Web API - Password Hashing: Weak key length",
395
+ msg: `${title("web", "Password Hashing")}: Weak key length`,
405
396
  desc: "Key length must be a number and at least 16 bytes (recommended 64)"
406
397
  });
407
398
  }
@@ -419,13 +410,13 @@ async function $hashPassword(password, options = {}) {
419
410
  baseKey,
420
411
  keyLength * 8
421
412
  );
422
- const saltStr = $convertBytesToStr(salt, outputEncoding);
413
+ const saltStr = $convertBytesToStr(salt, encoding);
423
414
  if (saltStr.error) return $err(saltStr.error);
424
- const hashedPasswordStr = $convertBytesToStr(bits, outputEncoding);
415
+ const hashedPasswordStr = $convertBytesToStr(bits, encoding);
425
416
  if (hashedPasswordStr.error) return $err(hashedPasswordStr.error);
426
417
  return $ok({ hash: hashedPasswordStr.result, salt: saltStr.result });
427
418
  } catch (error) {
428
- return $err({ msg: "Crypto Web API - Password Hashing: Failed to hash password", desc: $fmtError(error) });
419
+ return $err({ msg: `${title("web", "Password Hashing")}: Failed to hash password`, desc: $fmtError(error) });
429
420
  }
430
421
  }
431
422
  async function $verifyPassword(password, hashedPassword, salt, options = {}) {
@@ -433,15 +424,15 @@ async function $verifyPassword(password, hashedPassword, salt, options = {}) {
433
424
  const digest = options.digest ?? "sha512";
434
425
  if (!(digest in DIGEST_ALGORITHMS)) return false;
435
426
  const digestAlgo = DIGEST_ALGORITHMS[digest];
436
- const inputEncoding = options.inputEncoding ?? "base64url";
437
- if (!ENCODINGS.includes(inputEncoding)) return false;
427
+ const encoding = options.encoding ?? "base64url";
428
+ if (!CIPHER_ENCODING.includes(encoding)) return false;
438
429
  const iterations = options.iterations ?? 32e4;
439
430
  if (typeof iterations !== "number" || iterations < 1e3) return false;
440
431
  const keyLength = options.keyLength ?? 64;
441
432
  if (typeof keyLength !== "number" || keyLength < 16) return false;
442
- const saltBytes = $convertStrToBytes(salt, "base64url");
433
+ const saltBytes = $convertStrToBytes(salt, encoding);
443
434
  if (saltBytes.error) return false;
444
- const hashedPasswordBytes = $convertStrToBytes(hashedPassword, "base64url");
435
+ const hashedPasswordBytes = $convertStrToBytes(hashedPassword, encoding);
445
436
  if (hashedPasswordBytes.error) return false;
446
437
  try {
447
438
  const baseKey = await crypto.subtle.importKey(
@@ -463,18 +454,22 @@ async function $verifyPassword(password, hashedPassword, salt, options = {}) {
463
454
  keyLength * 8
464
455
  )
465
456
  );
457
+ if (bits === void 0 || hashedPasswordBytes.result === void 0) return false;
466
458
  if (bits.length !== hashedPasswordBytes.result.length) return false;
467
- let isMatch = true;
459
+ let diff = 0;
468
460
  for (let i = 0; i < bits.length; i++) {
469
- if (bits[i] !== hashedPasswordBytes.result[i]) isMatch = false;
461
+ diff |= bits[i] ^ hashedPasswordBytes.result[i];
470
462
  }
471
- return isMatch;
463
+ return diff === 0;
472
464
  } catch {
473
465
  return false;
474
466
  }
475
467
  }
476
468
 
477
469
  // src/web/kit.ts
470
+ function isWebSecretKey(x) {
471
+ return $isSecretKey(x, "web") !== null;
472
+ }
478
473
  function tryGenerateUuid() {
479
474
  return $generateUuid();
480
475
  }
@@ -531,14 +526,6 @@ async function hash(data, options = {}) {
531
526
  if (error) throw new Error($fmtResultErr(error));
532
527
  return result;
533
528
  }
534
- async function tryHashObj(data, options = {}) {
535
- return await $hashObj(data, options);
536
- }
537
- async function hashObj(data, options = {}) {
538
- const { result, error } = await $hashObj(data, options);
539
- if (error) throw new Error($fmtResultErr(error));
540
- return result;
541
- }
542
529
  async function tryHashPassword(password, options = {}) {
543
530
  return await $hashPassword(password, options);
544
531
  }
@@ -575,6 +562,6 @@ function convertEncoding(data, from, to) {
575
562
  return result;
576
563
  }
577
564
 
578
- export { convertBytesToStr, convertEncoding, convertStrToBytes, createSecretKey, decrypt, decryptObj, encrypt, encryptObj, generateUuid, hash, hashObj, hashPassword, kit_exports, tryConvertBytesToStr, tryConvertEncoding, tryConvertStrToBytes, tryCreateSecretKey, tryDecrypt, tryDecryptObj, tryEncrypt, tryEncryptObj, tryGenerateUuid, tryHash, tryHashObj, tryHashPassword, verifyPassword };
579
- //# sourceMappingURL=chunk-BNQERV4S.js.map
580
- //# sourceMappingURL=chunk-BNQERV4S.js.map
565
+ 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-LHB5NXYW.js.map
567
+ //# sourceMappingURL=chunk-LHB5NXYW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/web/kit.ts","../src/web/web-encode.ts","../src/web/web-encrypt.ts"],"names":["error","hash"],"mappings":"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","file":"chunk-LHB5NXYW.js","sourcesContent":["import { $fmtResultErr, type Result } from '~/helpers/error';\r\nimport type {\r\n CreateSecretKeyOptions,\r\n DecryptOptions,\r\n Encoding,\r\n EncryptOptions,\r\n HashOptions,\r\n HashPasswordOptions,\r\n SecretKey,\r\n VerifyPasswordOptions,\r\n} from '~/helpers/types';\r\nimport { $isSecretKey } from '~/helpers/validate';\r\nimport { $convertBytesToStr, $convertEncoding, $convertStrToBytes } from './web-encode';\r\nimport {\r\n $createSecretKey,\r\n $decrypt,\r\n $decryptObj,\r\n $encrypt,\r\n $encryptObj,\r\n $generateUuid,\r\n $hash,\r\n $hashPassword,\r\n $verifyPassword,\r\n} from './web-encrypt';\r\n\r\n/**\r\n * Type guard to check if the provided value is a SecretKey object for Web (Deno, Bun, Cloudflare included) environment.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Checking if the key in your hand is the right kind of key for the lock.\r\n *\r\n * @param x - The value to check.\r\n * @returns True if the value is a SecretKey object for Web, false otherwise.\r\n */\r\nexport function isWebSecretKey(x: unknown): x is SecretKey<'web'> {\r\n return $isSecretKey(x, 'web') !== null;\r\n}\r\n\r\n/**\r\n * Safely generates a UUID (v4) (non-throwing).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * It's like giving your pet a name tag with a super random name made of numbers and letters.\r\n * The chance of two pets getting the same name tag is practically zero, and it's very hard to guess!\r\n *\r\n * @returns A `Result` containing the UUID string or an error.\r\n */\r\nexport function tryGenerateUuid(): Result<string> {\r\n return $generateUuid();\r\n}\r\n\r\n/**\r\n * Generates a UUID (v4) (throwing).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * It's like giving your pet a name tag with a super random name made of numbers and letters.\r\n * The chance of two pets getting the same name tag is practically zero, and it's very hard to guess!\r\n *\r\n * @returns A UUID string.\r\n * @throws {Error} If UUID generation fails.\r\n */\r\nexport function generateUuid(): string {\r\n const { result, error } = $generateUuid();\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely derives a `SecretKey` from the provided string for encryption/decryption (non-throwing).\r\n *\r\n * Uses HKDF to derive a key from the input string.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Imagine you want to create a special key for future use to lock your treasure box (data).\r\n * So, you stir in some secret ingredients (like salt and info) to make sure your key is one-of-a-kind.\r\n *\r\n * @param secret - The input string to derive the `SecretKey` from.\r\n * @param options.algorithm - The encryption algorithm to use (default: `'aes256gcm'`).\r\n * @param options.digest - The hash algorithm for HKDF (default: `'sha256'`).\r\n * @param options.salt - A salt string (default: `'cipher-kit-salt'`, must be ≥ 8 chars).\r\n * @param options.info - An info string (default: `'cipher-kit'`).\r\n * @returns A `Result` promise containing the derived `SecretKey` or an error.\r\n */\r\nexport async function tryCreateSecretKey(\r\n secret: string,\r\n options: CreateSecretKeyOptions = {},\r\n): Promise<Result<{ result: SecretKey<'web'> }>> {\r\n return await $createSecretKey(secret, options);\r\n}\r\n\r\n/**\r\n * Derives a `SecretKey` from the provided string for encryption/decryption (throwing).\r\n *\r\n * Uses HKDF to derive a key from the input string.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Imagine you want to create a special key for future use to lock your treasure box (data).\r\n * So, you stir in some secret ingredients (like salt and info) to make sure your key is one-of-a-kind.\r\n *\r\n * @param secret - The input string to derive the `SecretKey` from.\r\n * @param options.algorithm - The encryption algorithm to use (default: `'aes256gcm'`).\r\n * @param options.digest - The hash algorithm for HKDF (default: `'sha256'`).\r\n * @param options.salt - A salt string (default: `'cipher-kit-salt'`, must be ≥ 8 chars).\r\n * @param options.info - An info string (default: `'cipher-kit'`).\r\n * @returns A promise of the derived `SecretKey`.\r\n * @throws {Error} If key derivation fails.\r\n */\r\nexport async function createSecretKey(secret: string, options: CreateSecretKeyOptions = {}): Promise<SecretKey<'web'>> {\r\n const { result, error } = await $createSecretKey(secret, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely encrypts a UTF-8 string using the provided `SecretKey` (non-throwing).\r\n *\r\n * Output format: \"iv.cipherWithTag.\"\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You scramble a secret message with your special key,\r\n * creating a jumbled code that only someone with the right key can read.\r\n *\r\n * @param data - A UTF-8 string to encrypt.\r\n * @param secretKey - The `SecretKey` object used for encryption.\r\n * @param options.encoding - The encoding format for the output ciphertext (default: `'base64url'`).\r\n * @returns A `Result` promise containing the encrypted string in the specified format or an error.\r\n */\r\nexport async function tryEncrypt(\r\n data: string,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<Result<string>> {\r\n return await $encrypt(data, secretKey, options);\r\n}\r\n\r\n/**\r\n * Encrypts a UTF-8 string using the provided `SecretKey` (throwing).\r\n *\r\n * Output format: \"iv.cipherWithTag.\"\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You scramble a secret message with your special key,\r\n * creating a jumbled code that only someone with the right key can read.\r\n *\r\n * @param data - A UTF-8 string to encrypt.\r\n * @param secretKey - The `SecretKey` object used for encryption.\r\n * @param options.encoding - The encoding format for the output ciphertext (default: `'base64url'`).\r\n * @returns A promise with the encrypted string in the specified format.\r\n * @throws {Error} If the input data or key is invalid, or if encryption fails.\r\n */\r\nexport async function encrypt(\r\n data: string,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<string> {\r\n const { result, error } = await $encrypt(data, secretKey, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely decrypts the input string using the provided `SecretKey` (non-throwing).\r\n *\r\n * Expects input in the format \"iv.cipherWithTag.\" and returns the decrypted UTF-8 string.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You take a scrambled secret message and use your special key to unscramble it,\r\n * revealing the original message inside.\r\n *\r\n * @param encrypted - The input string to decrypt, in the format \"iv.cipherWithTag.\".\r\n * @param secretKey - The `SecretKey` object used for decryption.\r\n * @param options.encoding - The encoding format for the input ciphertext (default: `'base64url'`).\r\n * @returns A `Result` promise containing the decrypted UTF-8 string or an error.\r\n */\r\nexport async function tryDecrypt(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<Result<string>> {\r\n return await $decrypt(encrypted, secretKey, options);\r\n}\r\n\r\n/**\r\n * Decrypts the input string using the provided `SecretKey` (throwing).\r\n *\r\n * Expects input in the format \"iv.cipherWithTag.\" and returns the decrypted UTF-8 string.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You take a scrambled secret message and use your special key to unscramble it,\r\n * revealing the original message inside.\r\n *\r\n * @param encrypted - The input string to decrypt, in the format \"iv.cipherWithTag.\".\r\n * @param secretKey - The `SecretKey` object used for decryption.\r\n * @param options.encoding - The encoding format for the input ciphertext (default: `'base64url'`).\r\n * @returns A promise with the decrypted UTF-8 string.\r\n * @throws {Error} If the input data or key is invalid, or if decryption fails.\r\n */\r\nexport async function decrypt(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<string> {\r\n const { result, error } = await $decrypt(encrypted, secretKey, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely encrypts a plain object using the provided `SecretKey` (non-throwing).\r\n *\r\n * Only plain objects (POJOs) are accepted. Class instances, Maps, Sets, etc. are rejected.\r\n *\r\n * Output format: \"iv.cipherWithTag.\"\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Imagine you have a toy box (an object) that you want to keep secret.\r\n * So, you take a picture of your toy box (convert it to JSON), and scramble that with\r\n * your special key, creating a jumbled code that only someone with the right key can read.\r\n *\r\n * @param data - A plain object to encrypt.\r\n * @param secretKey - The `SecretKey` object used for encryption.\r\n * @param options.encoding - The encoding format for the output ciphertext (default: `'base64url'`).\r\n * @returns A `Result` promise containing the encrypted string in the specified format or an error.\r\n */\r\nexport async function tryEncryptObj<T extends object = Record<string, unknown>>(\r\n data: T,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<Result<string>> {\r\n return await $encryptObj(data, secretKey, options);\r\n}\r\n\r\n/**\r\n * Encrypts a plain object using the provided `SecretKey` (throwing).\r\n *\r\n * Only plain objects (POJOs) are accepted. Class instances, Maps, Sets, etc. are rejected.\r\n *\r\n * Output format: \"iv.cipherWithTag.\"\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Imagine you have a toy box (an object) that you want to keep secret.\r\n * So, you take a picture of your toy box (convert it to JSON), and scramble that with\r\n * your special key, creating a jumbled code that only someone with the right key can read.\r\n *\r\n * @param data - A plain object to encrypt.\r\n * @param secretKey - The `SecretKey` object used for encryption.\r\n * @param options.encoding - The encoding format for the output ciphertext (default: `'base64url'`).\r\n * @returns A promise with the encrypted string in the specified format.\r\n * @throws {Error} If the input data or key is invalid, or if encryption fails.\r\n */\r\nexport async function encryptObj<T extends object = Record<string, unknown>>(\r\n data: T,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<string> {\r\n const { result, error } = await $encryptObj(data, secretKey, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely decrypts an encrypted JSON string into an object (non-throwing).\r\n *\r\n * Expects input in the format `\"iv.cipherWithTag.\"` and returns a plain object.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You rebuild your toy box (an object) by unscrambling the jumbled code (encrypted text),\r\n * using your special key to open it.\r\n *\r\n * @template T - The expected shape of the decrypted object.\r\n * @param encrypted - The encrypted string (format: `\"iv.cipherWithTag.\"`).\r\n * @param secretKey - The `SecretKey` used for decryption.\r\n * @param options.encoding - Input ciphertext encoding (default: `'base64url'`).\r\n * @returns A `Result` promise with the decrypted object on success, or an error.\r\n */\r\nexport async function tryDecryptObj<T extends object = Record<string, unknown>>(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<Result<{ result: T }>> {\r\n return await $decryptObj<T>(encrypted, secretKey, options);\r\n}\r\n\r\n/**\r\n * Decrypts an encrypted JSON string into an object (throwing).\r\n *\r\n * Expects input in the format `\"iv.cipherWithTag.\"` and returns a plain object.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * You rebuild your toy box (an object) by unscrambling the jumbled code (encrypted text),\r\n * using your special key to open it.\r\n *\r\n * @template T - The expected shape of the decrypted object.\r\n * @param encrypted - The encrypted string (format: `\"iv.cipherWithTag.\"`).\r\n * @param secretKey - The `SecretKey` used for decryption.\r\n * @param options.encoding - Input ciphertext encoding (default: `'base64url'`).\r\n * @returns A promise with the decrypted object.\r\n * @throws {Error} If decryption or JSON parsing fails.\r\n */\r\nexport async function decryptObj<T extends object = Record<string, unknown>>(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<T> {\r\n const { result, error } = await $decryptObj<T>(encrypted, secretKey, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely hashes a UTF-8 string (non-throwing).\r\n *\r\n * Uses the selected digest (default: `'sha256'`) and returns the hash\r\n * in the chosen encoding (default: `'base64url'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Like putting something in a blender and getting a smoothie, you can’t get the original ingredients back,\r\n * but the smoothie is always the same if you use the same ingredients.\r\n *\r\n * @param data - The input string to hash.\r\n * @param options.digest - Hash algorithm (`'sha256' | 'sha384' | 'sha512'`, default: `'sha256'`).\r\n * @param options.encoding - Output encoding (`'base64' | 'base64url' | 'hex'`, default: `'base64url'`).\r\n * @returns A `Result` promise with the hash string or an error.\r\n */\r\nexport async function tryHash(data: string, options: HashOptions = {}): Promise<Result<string>> {\r\n return await $hash(data, options);\r\n}\r\n\r\n/**\r\n * Hashes a UTF-8 string (throwing).\r\n *\r\n * Uses the selected digest (default: `'sha256'`) and returns the hash\r\n * in the chosen encoding (default: `'base64url'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * Like putting something in a blender and getting a smoothie, you can’t get the original ingredients back,\r\n * but the smoothie is always the same if you use the same ingredients.\r\n *\r\n * @param data - The input string to hash.\r\n * @param options.digest - Hash algorithm (`'sha256' | 'sha384' | 'sha512'`, default: `'sha256'`).\r\n * @param options.encoding - Output encoding (`'base64' | 'base64url' | 'hex'`, default: `'base64url'`).\r\n * @returns A promise of the hashed string.\r\n * @throws {Error} If input is invalid or hashing fails.\r\n */\r\nexport async function hash(data: string, options: HashOptions = {}): Promise<string> {\r\n const { result, error } = await $hash(data, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely hashes a password using PBKDF2 (non-throwing).\r\n *\r\n * Uses strong defaults (`sha512`, 320k iterations, 64-byte key, 16-byte salt) and\r\n * returns `{ hash, salt }` encoded (default: `'base64url'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * We take your password, mix in some random salt, and stir many times.\r\n * The result is a super-secret soup that’s hard to copy.\r\n *\r\n * @param password - The password to hash.\r\n * @param options.digest - Hash algorithm (`'sha256' | 'sha384' | 'sha512'`; default: `'sha512'`).\r\n * @param options.encoding - Output encoding (`'base64' | 'base64url' | 'hex'`; default: `'base64url'`).\r\n * @param options.saltLength - Length of the random salt in bytes (default: `16` bytes, min: `8` bytes).\r\n * @param options.iterations - Number of iterations (default: `320000`, min: `1000`).\r\n * @param options.keyLength - Length of the derived key in bytes (default: `64` bytes, min: `16` bytes).\r\n * @returns A `Result` promise with `{ hash, salt }` or an error.\r\n */\r\nexport async function tryHashPassword(\r\n password: string,\r\n options: HashPasswordOptions = {},\r\n): Promise<Result<{ hash: string; salt: string }>> {\r\n return await $hashPassword(password, options);\r\n}\r\n\r\n/**\r\n * Hashes a password using PBKDF2 (throwing).\r\n *\r\n * Uses strong defaults (`sha512`, 320k iterations, 64-byte key, 16-byte salt) and\r\n * returns `{ hash, salt }` encoded (default: `'base64url'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * We take your password, mix in some random salt, and stir many times.\r\n * The result is a super-secret soup that’s hard to copy.\r\n *\r\n * @param password - The password to hash.\r\n * @param options.digest - Hash algorithm (`'sha256' | 'sha384' | 'sha512'`; default: `'sha512'`).\r\n * @param options.encoding - Output encoding (`'base64' | 'base64url' | 'hex'`; default: `'base64url'`).\r\n * @param options.saltLength - Length of the random salt in bytes (default: `16` bytes, min: `8` bytes).\r\n * @param options.iterations - Number of iterations (default: `320000`, min: `1000`).\r\n * @param options.keyLength - Length of the derived key in bytes (default: `64` bytes, min: `16` bytes).\r\n * @returns A promise with `{ hash, salt }` for storage.\r\n * @throws {Error} If inputs are invalid or hashing fails.\r\n */\r\nexport async function hashPassword(\r\n password: string,\r\n options: HashPasswordOptions = {},\r\n): Promise<{ hash: string; salt: string }> {\r\n const { hash, salt, error } = await $hashPassword(password, options);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return { hash, salt };\r\n}\r\n\r\n/**\r\n * Verifies a password against a stored PBKDF2 hash (non-throwing).\r\n *\r\n * Re-derives the key using the same parameters and compares in constant time, to prevent timing attacks.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * We follow the same recipe as when we made the secret.\r\n * If the new soup tastes exactly the same, the password is correct.\r\n *\r\n * @param password - The plain password to verify.\r\n * @param hashedPassword - The stored hash (encoded).\r\n * @param salt - The stored salt (encoded).\r\n * @param options.digest - Hash algorithm used during hashing (`'sha256' | 'sha384' | 'sha512'`; default: `'sha512'`).\r\n * @param options.encoding - Encoding of the stored hash and salt (`'base64' | 'base64url' | 'hex'`; default: `'base64url'`).\r\n * @param options.iterations - Number of iterations used during hashing (default: `320000`).\r\n * @param options.keyLength - Length of the derived key in bytes used during hashing (default: `64` bytes).\r\n * @returns A promise of boolean, `true` if the password matches, otherwise `false`.\r\n */\r\nexport async function verifyPassword(\r\n password: string,\r\n hashedPassword: string,\r\n salt: string,\r\n options: VerifyPasswordOptions = {},\r\n): Promise<boolean> {\r\n return await $verifyPassword(password, hashedPassword, salt, options);\r\n}\r\n\r\n/**\r\n * Safely converts a string to a `Uint8Array` using the specified encoding (non-throwing).\r\n *\r\n * Supported encodings: `'base64' | 'base64url' | 'hex' | 'utf8' | 'latin1'` (default: `'utf8'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * This turns your words into tiny computer building blocks (bytes) so computers can work with them.\r\n *\r\n * @param data - The input string to convert.\r\n * @param inputEncoding - The encoding of the input string (default: `'utf8'`).\r\n * @returns A `Result` with `{ result: Uint8Array }` or an error.\r\n */\r\nexport function tryConvertStrToBytes(\r\n data: string,\r\n inputEncoding: Encoding = 'utf8',\r\n): Result<{ result: Uint8Array<ArrayBuffer> }> {\r\n return $convertStrToBytes(data, inputEncoding);\r\n}\r\n\r\n/**\r\n * Converts a string to a `Uint8Array` using the specified encoding (throwing).\r\n *\r\n * Supported encodings: `'base64' | 'base64url' | 'hex' | 'utf8' | 'latin1'` (default: `'utf8'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * This turns your words into tiny computer building blocks (bytes) so computers can work with them.\r\n *\r\n * @param data - The input string to convert.\r\n * @param inputEncoding - The encoding of the input string (default: `'utf8'`).\r\n * @returns A `Uint8Array` containing the bytes.\r\n * @throws {Error} If input is invalid or conversion fails.\r\n */\r\nexport function convertStrToBytes(data: string, inputEncoding: Encoding = 'utf8'): Uint8Array<ArrayBuffer> {\r\n const { result, error } = $convertStrToBytes(data, inputEncoding);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely converts a `Uint8Array` or `ArrayBuffer` to a string using the specified encoding (non-throwing).\r\n *\r\n * Supported encodings: `'base64' | 'base64url' | 'hex' | 'utf8' | 'latin1'` (default: `'utf8'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * This turns the tiny computer building blocks (bytes) back into a readable sentence.\r\n *\r\n * @param data - The `Uint8Array` or `ArrayBuffer` to convert.\r\n * @param outputEncoding - The output encoding (default: `'utf8'`).\r\n * @returns A `Result` with the string or an error.\r\n */\r\nexport function tryConvertBytesToStr(\r\n data: Uint8Array | ArrayBuffer,\r\n outputEncoding: Encoding = 'utf8',\r\n): Result<string> {\r\n return $convertBytesToStr(data, outputEncoding);\r\n}\r\n\r\n/**\r\n * Converts a `Uint8Array` or `ArrayBuffer` to a string using the specified encoding (throwing).\r\n *\r\n * Supported encodings: `'base64' | 'base64url' | 'hex' | 'utf8' | 'latin1'` (default: `'utf8'`).\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * This turns the tiny computer building blocks (bytes) back into a readable sentence.\r\n *\r\n * @param data - The `Uint8Array` or `ArrayBuffer` to convert.\r\n * @param outputEncoding - The output encoding (default: `'utf8'`).\r\n * @returns The encoded string.\r\n * @throws {Error} If input is invalid or conversion fails.\r\n */\r\nexport function convertBytesToStr(data: Uint8Array | ArrayBuffer, outputEncoding: Encoding = 'utf8'): string {\r\n const { result, error } = $convertBytesToStr(data, outputEncoding);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n\r\n/**\r\n * Safely converts text between encodings (non-throwing).\r\n *\r\n * Example: convert `'utf8'` text to `'base64url'`, or `'hex'` to `'utf8'`.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * It’s like translating your sentence from one alphabet to another.\r\n *\r\n * @param data - The input string to convert.\r\n * @param from - The current encoding of `data`.\r\n * @param to - The target encoding for `data`.\r\n * @returns A `Result` with a string or an error.\r\n */\r\nexport function tryConvertEncoding(data: string, from: Encoding, to: Encoding): Result<string> {\r\n return $convertEncoding(data, from, to);\r\n}\r\n\r\n/**\r\n * Converts text between encodings (throwing).\r\n *\r\n * Example: convert `'utf8'` text to `'base64url'`, or `'hex'` to `'utf8'`.\r\n *\r\n * ### 🍼 Explain Like I'm Five\r\n * It’s like translating your sentence from one alphabet to another.\r\n *\r\n * @param data - The input string to convert.\r\n * @param from - The current encoding of `data`.\r\n * @param to - The target encoding for `data`.\r\n * @returns The converted string.\r\n * @throws {Error} If encodings are invalid or conversion fails.\r\n */\r\nexport function convertEncoding(data: string, from: Encoding, to: Encoding): string {\r\n const { result, error } = $convertEncoding(data, from, to);\r\n if (error) throw new Error($fmtResultErr(error));\r\n return result;\r\n}\r\n","import { ENCODING } from '~/helpers/consts';\r\nimport { $err, $fmtError, $ok, type Result } from '~/helpers/error';\r\nimport type { Encoding } from '~/helpers/types';\r\nimport { $isStr } from '~/helpers/validate';\r\n\r\nexport const textEncoder = new TextEncoder();\r\nexport const textDecoder = new TextDecoder();\r\n\r\nexport function $convertStrToBytes(\r\n data: string,\r\n inputEncoding: Encoding = 'utf8',\r\n): Result<{ result: Uint8Array<ArrayBuffer> }> {\r\n if (!$isStr(data)) {\r\n return $err({\r\n msg: 'Crypto Web API - String to Bytes: Empty data',\r\n desc: 'Data must be a non-empty string',\r\n });\r\n }\r\n if (!ENCODING.includes(inputEncoding)) {\r\n return $err({\r\n msg: `Crypto Web API - String to Bytes: Unsupported encoding: ${inputEncoding}`,\r\n desc: 'Use base64, base64url, hex, utf8, or latin1',\r\n });\r\n }\r\n\r\n try {\r\n const bytes = strToBytes[inputEncoding](data);\r\n return $ok({ result: bytes });\r\n } catch (error) {\r\n return $err({ msg: 'Crypto Web API - String to Bytes: Failed to convert data', desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport function $convertBytesToStr(data: Uint8Array | ArrayBuffer, outputEncoding: Encoding = 'utf8'): Result<string> {\r\n if (!(data instanceof ArrayBuffer || data instanceof Uint8Array)) {\r\n return $err({\r\n msg: 'Crypto Web API - Bytes to String: Invalid data type',\r\n desc: 'Data must be an ArrayBuffer or Uint8Array',\r\n });\r\n }\r\n if (!ENCODING.includes(outputEncoding)) {\r\n return $err({\r\n msg: `Crypto Web API - Bytes to String: Unsupported encoding: ${outputEncoding}`,\r\n desc: 'Use base64, base64url, hex, utf8, or latin1',\r\n });\r\n }\r\n try {\r\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\r\n const str = bytesToStr[outputEncoding](bytes);\r\n return $ok(str);\r\n } catch (error) {\r\n return $err({ msg: 'Crypto Web API - Bytes to String: Failed to convert data', desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport function $convertEncoding(data: string, from: Encoding, to: Encoding): Result<string> {\r\n if (!$isStr(data)) {\r\n return $err({\r\n msg: 'Crypto Web API - Convert Format: Empty data',\r\n desc: 'Data must be a non-empty string',\r\n });\r\n }\r\n if (!ENCODING.includes(from) || !ENCODING.includes(to)) {\r\n return $err({\r\n msg: `Crypto Web API - Convert Format: Unsupported encoding: from ${from} to ${to}`,\r\n desc: 'Use base64, base64url, hex, utf8, or latin1',\r\n });\r\n }\r\n\r\n const bytes = $convertStrToBytes(data, from);\r\n if (bytes.error) return $err({ msg: bytes.error.message, desc: bytes.error.description });\r\n\r\n const str = $convertBytesToStr(bytes.result, to);\r\n if (str.error) return $err({ msg: str.error.message, desc: str.error.description });\r\n\r\n return $ok({ result: str.result });\r\n}\r\n\r\nconst strToBytes = {\r\n base64: $fromBase64,\r\n base64url: $fromBase64Url,\r\n hex: $fromHex,\r\n latin1: $fromLatin1,\r\n utf8: (data: string) => textEncoder.encode(data),\r\n} as const satisfies Record<Encoding, (data: string) => Uint8Array<ArrayBuffer>>;\r\n\r\nconst bytesToStr = {\r\n base64: $toBase64,\r\n base64url: $toBase64Url,\r\n hex: $toHex,\r\n latin1: $toLatin1,\r\n utf8: (data: Uint8Array) => textDecoder.decode(data),\r\n} as const satisfies Record<Encoding, (data: Uint8Array) => string>;\r\n\r\nfunction $toLatin1(bytes: Uint8Array): string {\r\n let out = '';\r\n const chunk = 1 << 15; // 32KiB per chunk\r\n for (let i = 0; i < bytes.length; i += chunk) {\r\n out += String.fromCharCode(...bytes.subarray(i, i + chunk));\r\n }\r\n return out;\r\n}\r\n\r\nfunction $fromLatin1(data: string): Uint8Array<ArrayBuffer> {\r\n const out = new Uint8Array(data.length);\r\n for (let i = 0; i < data.length; i++) {\r\n const charCode = data.charCodeAt(i);\r\n if (charCode > 255) throw new Error('Invalid latin1 string');\r\n out[i] = charCode;\r\n }\r\n return out;\r\n}\r\n\r\nfunction $toBase64(bytes: Uint8Array): string {\r\n return btoa($toLatin1(bytes));\r\n}\r\n\r\nfunction $fromBase64(data: string): Uint8Array<ArrayBuffer> {\r\n return $fromLatin1(atob(data));\r\n}\r\n\r\nfunction $toBase64Url(bytes: Uint8Array): string {\r\n return $toBase64(bytes).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\r\n}\r\n\r\nfunction $fromBase64Url(data: string): Uint8Array<ArrayBuffer> {\r\n let base64 = data.replace(/-/g, '+').replace(/_/g, '/');\r\n const padLen = (4 - (base64.length % 4)) % 4;\r\n base64 += '='.repeat(padLen);\r\n return $fromBase64(base64);\r\n}\r\n\r\nfunction $toHex(bytes: Uint8Array): string {\r\n return Array.from(bytes)\r\n .map((b) => b.toString(16).padStart(2, '0'))\r\n .join('');\r\n}\r\n\r\nfunction $fromHex(data: string): Uint8Array<ArrayBuffer> {\r\n const clean = data.startsWith('0x') ? data.slice(2) : data;\r\n if (clean.length % 2 !== 0) throw new Error('Invalid hex string');\r\n const out = new Uint8Array(clean.length / 2);\r\n for (let i = 0; i < out.length; i++) {\r\n const byte = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\r\n if (Number.isNaN(byte)) throw new Error('Invalid hex string');\r\n out[i] = byte;\r\n }\r\n return out;\r\n}\r\n","import { CIPHER_ENCODING, DIGEST_ALGORITHMS, ENCRYPTION_ALGORITHMS } from '~/helpers/consts';\r\nimport { $err, $fmtError, $fmtResultErr, $ok, type Result, title } from '~/helpers/error';\r\nimport { $parseToObj, $stringifyObj } from '~/helpers/object';\r\nimport type {\r\n CreateSecretKeyOptions,\r\n DecryptOptions,\r\n EncryptOptions,\r\n HashOptions,\r\n HashPasswordOptions,\r\n SecretKey,\r\n VerifyPasswordOptions,\r\n} from '~/helpers/types';\r\nimport { $isSecretKey, $isStr, matchPattern } from '~/helpers/validate';\r\nimport { $convertBytesToStr, $convertStrToBytes, textEncoder } from './web-encode';\r\n\r\nexport function $generateUuid(): Result<string> {\r\n try {\r\n return $ok(crypto.randomUUID());\r\n } catch (error) {\r\n return $err({ msg: `${title('web', 'UUID Generation')}: Failed to generate UUID`, desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport async function $createSecretKey(\r\n secret: string,\r\n options: CreateSecretKeyOptions = {},\r\n): Promise<Result<{ result: SecretKey<'web'> }>> {\r\n if (!$isStr(secret)) {\r\n return $err({ msg: `${title('web', 'Key Generation')}: Empty Secret`, desc: 'Secret must be a non-empty string' });\r\n }\r\n\r\n const algorithm = options.algorithm ?? 'aes256gcm';\r\n if (!(algorithm in ENCRYPTION_ALGORITHMS)) {\r\n return $err({\r\n msg: `${title('web', 'Key Generation')}: Unsupported algorithm: ${algorithm}`,\r\n desc: `Supported algorithms are: ${Object.keys(ENCRYPTION_ALGORITHMS).join(', ')}`,\r\n });\r\n }\r\n\r\n const digest = options.digest ?? 'sha256';\r\n if (!(digest in DIGEST_ALGORITHMS)) {\r\n return $err({\r\n msg: `${title('web', 'Key Generation')}: Unsupported digest: ${digest}`,\r\n desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(', ')}`,\r\n });\r\n }\r\n\r\n const salt = options.salt ?? 'cipher-kit-salt';\r\n if (!$isStr(salt, 8)) {\r\n return $err({\r\n msg: `${title('web', 'Key Generation')}: Weak salt`,\r\n desc: 'Salt must be a non-empty string with at least 8 characters',\r\n });\r\n }\r\n\r\n const info = options.info ?? 'cipher-kit';\r\n if (!$isStr(info)) {\r\n return $err({\r\n msg: `${title('web', 'Key Generation')}: Invalid info`,\r\n desc: 'Info must be a non-empty string',\r\n });\r\n }\r\n\r\n const encryptAlgo = ENCRYPTION_ALGORITHMS[algorithm];\r\n const digestAlgo = DIGEST_ALGORITHMS[digest];\r\n\r\n try {\r\n const ikm = await crypto.subtle.importKey('raw', textEncoder.encode(secret.normalize('NFKC')), 'HKDF', false, [\r\n 'deriveKey',\r\n ]);\r\n const key = await crypto.subtle.deriveKey(\r\n {\r\n name: 'HKDF',\r\n hash: digestAlgo.web,\r\n salt: textEncoder.encode(salt.normalize('NFKC')),\r\n info: textEncoder.encode(info.normalize('NFKC')),\r\n },\r\n ikm,\r\n { name: encryptAlgo.web, length: encryptAlgo.keyBytes * 8 },\r\n true,\r\n ['encrypt', 'decrypt'],\r\n );\r\n const secretKey = Object.freeze({\r\n platform: 'web',\r\n digest: digest,\r\n algorithm: algorithm,\r\n key: key,\r\n }) as SecretKey<'web'>;\r\n\r\n return $ok({ result: secretKey });\r\n } catch (error) {\r\n return $err({\r\n msg: `${title('web', 'Key Generation')}: Failed to create secret key`,\r\n desc: $fmtError(error),\r\n });\r\n }\r\n}\r\n\r\nexport async function $encrypt(\r\n data: string,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<Result<string>> {\r\n if (!$isStr(data)) {\r\n return $err({\r\n msg: `${title('web', 'Encryption')}: Empty data for encryption`,\r\n desc: 'Data must be a non-empty string',\r\n });\r\n }\r\n\r\n const encoding = options.encoding ?? 'base64url';\r\n if (!CIPHER_ENCODING.includes(encoding)) {\r\n return $err({\r\n msg: `${title('web', 'Encryption')}: Unsupported output encoding: ${encoding}`,\r\n desc: 'Use base64, base64url, or hex',\r\n });\r\n }\r\n\r\n const injectedKey = $isSecretKey(secretKey, 'web');\r\n if (!injectedKey) {\r\n return $err({\r\n msg: `${title('web', 'Encryption')}: Invalid Secret Key`,\r\n desc: 'Expected a Web SecretKey',\r\n });\r\n }\r\n\r\n const { result, error } = $convertStrToBytes(data, 'utf8');\r\n if (error) return $err(error);\r\n\r\n try {\r\n const iv = crypto.getRandomValues(new Uint8Array(injectedKey.injected.ivLength));\r\n const cipherWithTag = await crypto.subtle.encrypt(\r\n { name: injectedKey.injected.web, iv: iv },\r\n injectedKey.key,\r\n result,\r\n );\r\n\r\n const ivStr = $convertBytesToStr(iv, encoding);\r\n const cipherStr = $convertBytesToStr(cipherWithTag, encoding);\r\n\r\n if (ivStr.error || cipherStr.error) {\r\n return $err({\r\n msg: `${title('web', 'Encryption')}: Failed to convert IV or encrypted data`,\r\n desc: `Conversion error: ${$fmtResultErr(ivStr.error || cipherStr.error)}`,\r\n });\r\n }\r\n\r\n return $ok(`${ivStr.result}.${cipherStr.result}.`);\r\n } catch (error) {\r\n return $err({ msg: `${title('web', 'Encryption')}: Failed to encrypt data`, desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport async function $decrypt(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<Result<string>> {\r\n if (matchPattern(encrypted, 'web') === false) {\r\n return $err({\r\n msg: `${title('web', 'Decryption')}: Invalid encrypted data format`,\r\n desc: 'Encrypted data must be in the format \"iv.cipherWithTag.\"',\r\n });\r\n }\r\n\r\n const encoding = options.encoding ?? 'base64url';\r\n if (!CIPHER_ENCODING.includes(encoding)) {\r\n return $err({\r\n msg: `${title('web', 'Decryption')}: Unsupported input encoding: ${encoding}`,\r\n desc: 'Use base64, base64url, or hex',\r\n });\r\n }\r\n\r\n const [iv, encryptedWithTag] = encrypted.split('.', 3);\r\n if (!$isStr(iv) || !$isStr(encryptedWithTag)) {\r\n return $err({\r\n msg: `${title('web', 'Decryption')}: Invalid encrypted data`,\r\n desc: 'Encrypted data must contain valid IV, encrypted and tag components',\r\n });\r\n }\r\n\r\n const injectedKey = $isSecretKey(secretKey, 'web');\r\n if (!injectedKey) {\r\n return $err({\r\n msg: `${title('web', 'Decryption')}: Invalid Secret Key`,\r\n desc: 'Expected a Web SecretKey',\r\n });\r\n }\r\n\r\n const ivBytes = $convertStrToBytes(iv, encoding);\r\n const cipherWithTagBytes = $convertStrToBytes(encryptedWithTag, encoding);\r\n\r\n if (ivBytes.error || cipherWithTagBytes.error) {\r\n return $err({\r\n msg: `${title('web', 'Decryption')}: Failed to convert IV or encrypted data`,\r\n desc: `Conversion error: ${$fmtResultErr(ivBytes.error || cipherWithTagBytes.error)}`,\r\n });\r\n }\r\n\r\n try {\r\n const decrypted = await crypto.subtle.decrypt(\r\n { name: injectedKey.injected.web, iv: ivBytes.result },\r\n injectedKey.key,\r\n cipherWithTagBytes.result,\r\n );\r\n\r\n return $convertBytesToStr(decrypted, 'utf8');\r\n } catch (error) {\r\n return $err({ msg: `${title('web', 'Decryption')}: Failed to decrypt data`, desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport async function $encryptObj<T extends object = Record<string, unknown>>(\r\n data: T,\r\n secretKey: SecretKey<'web'>,\r\n options: EncryptOptions = {},\r\n): Promise<Result<string>> {\r\n const { result, error } = $stringifyObj(data);\r\n if (error) return $err(error);\r\n return await $encrypt(result, secretKey, options);\r\n}\r\n\r\nexport async function $decryptObj<T extends object = Record<string, unknown>>(\r\n encrypted: string,\r\n secretKey: SecretKey<'web'>,\r\n options: DecryptOptions = {},\r\n): Promise<Result<{ result: T }>> {\r\n const { result, error } = await $decrypt(encrypted, secretKey, options);\r\n if (error) return $err(error);\r\n return $parseToObj<T>(result);\r\n}\r\n\r\nexport async function $hash(data: string, options: HashOptions = {}): Promise<Result<string>> {\r\n if (!$isStr(data)) {\r\n return $err({ msg: `${title('web', 'Hashing')}: Empty data for hashing`, desc: 'Data must be a non-empty string' });\r\n }\r\n\r\n const encoding = options.encoding ?? 'base64url';\r\n if (!CIPHER_ENCODING.includes(encoding)) {\r\n return $err({\r\n msg: `${title('web', 'Hashing')}: Unsupported output encoding: ${encoding}`,\r\n desc: 'Use base64, base64url, or hex',\r\n });\r\n }\r\n\r\n const digest = options.digest ?? 'sha256';\r\n if (!(digest in DIGEST_ALGORITHMS)) {\r\n return $err({\r\n msg: `${title('web', 'Hashing')}: Unsupported digest: ${digest}`,\r\n desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(', ')}`,\r\n });\r\n }\r\n const digestAlgo = DIGEST_ALGORITHMS[digest];\r\n\r\n const { result, error } = $convertStrToBytes(data, 'utf8');\r\n if (error) return $err(error);\r\n\r\n try {\r\n const hashed = await crypto.subtle.digest(digestAlgo.web, result);\r\n return $convertBytesToStr(hashed, encoding);\r\n } catch (error) {\r\n return $err({ msg: `${title('web', 'Hashing')}: Failed to hash data`, desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport async function $hashPassword(\r\n password: string,\r\n options: HashPasswordOptions = {},\r\n): Promise<Result<{ hash: string; salt: string }>> {\r\n if (!$isStr(password)) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Empty password`,\r\n desc: 'Password must be a non-empty string',\r\n });\r\n }\r\n\r\n const digest = options.digest ?? 'sha512';\r\n if (!(digest in DIGEST_ALGORITHMS)) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Unsupported digest: ${digest}`,\r\n desc: `Supported digests are: ${Object.keys(DIGEST_ALGORITHMS).join(', ')}`,\r\n });\r\n }\r\n const digestAlgo = DIGEST_ALGORITHMS[digest];\r\n\r\n const encoding = options.encoding ?? 'base64url';\r\n if (!CIPHER_ENCODING.includes(encoding)) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Unsupported output encoding: ${encoding}`,\r\n desc: 'Use base64, base64url, or hex',\r\n });\r\n }\r\n\r\n const saltLength = options.saltLength ?? 16;\r\n if (typeof saltLength !== 'number' || saltLength < 8) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Weak salt length`,\r\n desc: 'Salt length must be a number and at least 8 bytes (recommended 16)',\r\n });\r\n }\r\n\r\n const iterations = options.iterations ?? 320_000;\r\n if (typeof iterations !== 'number' || iterations < 1000) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Weak iteration count`,\r\n desc: 'Iterations must be a number and at least 1000 (recommended 320,000 or more)',\r\n });\r\n }\r\n\r\n const keyLength = options.keyLength ?? 64;\r\n if (typeof keyLength !== 'number' || keyLength < 16) {\r\n return $err({\r\n msg: `${title('web', 'Password Hashing')}: Weak key length`,\r\n desc: 'Key length must be a number and at least 16 bytes (recommended 64)',\r\n });\r\n }\r\n\r\n try {\r\n const salt = crypto.getRandomValues(new Uint8Array(saltLength));\r\n const baseKey = await crypto.subtle.importKey(\r\n 'raw',\r\n textEncoder.encode(password.normalize('NFKC')),\r\n 'PBKDF2',\r\n false,\r\n ['deriveBits'],\r\n );\r\n const bits = await crypto.subtle.deriveBits(\r\n { name: 'PBKDF2', salt, iterations: iterations, hash: digestAlgo.web },\r\n baseKey,\r\n keyLength * 8,\r\n );\r\n\r\n const saltStr = $convertBytesToStr(salt, encoding);\r\n if (saltStr.error) return $err(saltStr.error);\r\n\r\n const hashedPasswordStr = $convertBytesToStr(bits, encoding);\r\n if (hashedPasswordStr.error) return $err(hashedPasswordStr.error);\r\n\r\n return $ok({ hash: hashedPasswordStr.result, salt: saltStr.result });\r\n } catch (error) {\r\n return $err({ msg: `${title('web', 'Password Hashing')}: Failed to hash password`, desc: $fmtError(error) });\r\n }\r\n}\r\n\r\nexport async function $verifyPassword(\r\n password: string,\r\n hashedPassword: string,\r\n salt: string,\r\n options: VerifyPasswordOptions = {},\r\n): Promise<boolean> {\r\n if (!$isStr(password) || !$isStr(hashedPassword) || !$isStr(salt)) return false;\r\n\r\n const digest = options.digest ?? 'sha512';\r\n if (!(digest in DIGEST_ALGORITHMS)) return false;\r\n const digestAlgo = DIGEST_ALGORITHMS[digest];\r\n\r\n const encoding = options.encoding ?? 'base64url';\r\n if (!CIPHER_ENCODING.includes(encoding)) return false;\r\n\r\n const iterations = options.iterations ?? 320_000;\r\n if (typeof iterations !== 'number' || iterations < 1000) return false;\r\n\r\n const keyLength = options.keyLength ?? 64;\r\n if (typeof keyLength !== 'number' || keyLength < 16) return false;\r\n\r\n const saltBytes = $convertStrToBytes(salt, encoding);\r\n if (saltBytes.error) return false;\r\n\r\n const hashedPasswordBytes = $convertStrToBytes(hashedPassword, encoding);\r\n if (hashedPasswordBytes.error) return false;\r\n\r\n try {\r\n const baseKey = await crypto.subtle.importKey(\r\n 'raw',\r\n textEncoder.encode(password.normalize('NFKC')),\r\n 'PBKDF2',\r\n false,\r\n ['deriveBits'],\r\n );\r\n\r\n const bits = new Uint8Array(\r\n await crypto.subtle.deriveBits(\r\n {\r\n name: 'PBKDF2',\r\n salt: saltBytes.result,\r\n iterations: iterations,\r\n hash: digestAlgo.web,\r\n },\r\n baseKey,\r\n keyLength * 8,\r\n ),\r\n );\r\n\r\n if (bits === undefined || hashedPasswordBytes.result === undefined) return false;\r\n if (bits.length !== hashedPasswordBytes.result.length) return false;\r\n\r\n let diff = 0;\r\n for (let i = 0; i < bits.length; i++) {\r\n diff |= (bits[i] as number) ^ (hashedPasswordBytes.result[i] as number);\r\n }\r\n return diff === 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n"]}