@zudojs/crypto 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertProviderCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { AES_GCM } from "../cryptoConstants/cryptoConstants.type.js";
3
4
  import { CryptoOperation } from "@zudojs/errors";
4
5
  import { cipherError } from "../cryptoErrors/cryptoErrors.helper.js";
@@ -10,6 +11,7 @@ export async function encrypt(plaintext, key, options = {}) {
10
11
  throw cipherError(`AES-256-GCM iv must be ${AES_GCM.IV_BYTES} bytes.`, CryptoOperation.ENCRYPT, "aes-256-gcm");
11
12
  }
12
13
  const provider = options.provider ?? getDefaultCryptoProvider();
14
+ assertProviderCapability(provider, "encryption", CryptoOperation.ENCRYPT);
13
15
  const encrypted = await provider.encrypt({
14
16
  key,
15
17
  plaintext,
@@ -37,6 +39,7 @@ export async function decrypt(ciphertext, key, iv, authTag, aad, provider = getD
37
39
  authTag.byteLength !== AES_GCM.AUTH_TAG_BYTES) {
38
40
  throw cipherError(`AES-256-GCM authentication tag must be ${AES_GCM.AUTH_TAG_BYTES} bytes.`, CryptoOperation.DECRYPT, "aes-256-gcm");
39
41
  }
42
+ assertProviderCapability(provider, "encryption", CryptoOperation.DECRYPT);
40
43
  return provider.decrypt({
41
44
  key,
42
45
  encrypted: {
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertHashCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { isHashAlgorithmName } from "../cryptoProvider/cryptoProvider.type.js";
3
4
  import { encodeDigest } from "./cryptoHash.codec.js";
4
5
  /**
@@ -13,6 +14,7 @@ export async function hash(input, options = {}) {
13
14
  throw new TypeError(`Unsupported hash algorithm: ${String(algorithm)}.`);
14
15
  }
15
16
  const provider = options.provider ?? getDefaultCryptoProvider();
17
+ assertHashCapability(provider);
16
18
  const digest = await provider.hash(algorithm, input);
17
19
  const encoding = options.encoding ?? "hex";
18
20
  return Object.freeze({
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertHmacCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { isHmacAlgorithmName } from "../cryptoProvider/cryptoProvider.type.js";
3
4
  import { KEY_SIZE } from "../cryptoConstants/cryptoConstants.type.js";
4
5
  import { encodeDigest } from "./cryptoHash.codec.js";
@@ -18,6 +19,7 @@ export async function hmac(input, key, algorithm = "sha256", encoding = "hex", p
18
19
  if (key.byteLength < KEY_SIZE.MIN_HMAC_KEY_BYTES) {
19
20
  throw new RangeError(`HMAC key must be at least ${KEY_SIZE.MIN_HMAC_KEY_BYTES} bytes.`);
20
21
  }
22
+ assertHmacCapability(provider);
21
23
  const digest = await provider.hmac(algorithm, key, input);
22
24
  return encodeDigest(digest, encoding);
23
25
  }
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertHmacCapability, assertRandomCapability, } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { encode } from "../cryptoEncoding/cryptoEncoding.core.js";
3
4
  import { CryptoOperation } from "@zudojs/errors";
4
5
  import { keyError } from "../cryptoErrors/cryptoErrors.helper.js";
@@ -58,6 +59,8 @@ function validateKeyBytes(bytes, algorithm) {
58
59
  * Hashing and key-id generation are delegated to the supplied provider.
59
60
  */
60
61
  export async function createCryptoKey(bytes, options, provider = getDefaultCryptoProvider()) {
62
+ assertHmacCapability(provider);
63
+ assertRandomCapability(provider);
61
64
  validateKeyBytes(bytes, options.algorithm);
62
65
  const keyBytes = new Uint8Array(bytes);
63
66
  const digest = await provider.hmac("sha256", CRYPTO_KEY_FINGERPRINT_LABEL, keyBytes);
@@ -90,6 +93,7 @@ export async function generateCryptoKey(length, options, provider = getDefaultCr
90
93
  if (!Number.isInteger(length) || length <= 0) {
91
94
  throw new RangeError("Cryptographic key length must be a positive integer.");
92
95
  }
96
+ assertRandomCapability(provider);
93
97
  const bytes = await provider.randomBytes(length);
94
98
  return createCryptoKey(bytes, options, provider);
95
99
  }
@@ -1,4 +1,6 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { CryptoOperation } from "@zudojs/errors";
3
+ import { assertProviderCapability, assertRandomCapability, } from "../cryptoProvider/cryptoProvider.capability.js";
2
4
  import { CryptoAlgorithm } from "../cryptoConstants/cryptoConstants.type.js";
3
5
  import { PASSWORD_HASH } from "../cryptoConstants/cryptoConstants.security.js";
4
6
  import { validatePbkdf2Options, validateScryptOptions, } from "./cryptoKeyDerivation.validate.js";
@@ -20,6 +22,8 @@ function pbkdf2Label(digest) {
20
22
  */
21
23
  export async function derivePbkdf2(password, options = {}) {
22
24
  const provider = options.provider ?? getDefaultCryptoProvider();
25
+ assertProviderCapability(provider, "keyDerivation", CryptoOperation.KEY_DERIVATION);
26
+ assertRandomCapability(provider);
23
27
  const iterations = options.iterations ?? PASSWORD_HASH.PBKDF2.ITERATIONS;
24
28
  const keyLength = options.keyLength ?? 32;
25
29
  const digest = options.digest ?? "sha256";
@@ -49,6 +53,8 @@ export async function derivePbkdf2(password, options = {}) {
49
53
  */
50
54
  export async function deriveScrypt(password, options = {}) {
51
55
  const provider = options.provider ?? getDefaultCryptoProvider();
56
+ assertProviderCapability(provider, "keyDerivation", CryptoOperation.KEY_DERIVATION);
57
+ assertRandomCapability(provider);
52
58
  const keyLength = options.keyLength ?? 32;
53
59
  const cost = options.cost ?? PASSWORD_HASH.SCRYPT.COST;
54
60
  const blockSize = options.blockSize ?? PASSWORD_HASH.SCRYPT.BLOCK_SIZE;
@@ -1,8 +1,10 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  /**
3
4
  * Creates a random salt.
4
5
  */
5
6
  export async function generateSalt(length = 16, provider = getDefaultCryptoProvider()) {
7
+ assertRandomCapability(provider);
6
8
  if (!Number.isInteger(length) || length < 16) {
7
9
  throw new RangeError("Salt length must be an integer of at least 16 bytes.");
8
10
  }
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertPasswordHashingCapability, assertRandomCapability, } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { CryptoAlgorithm } from "../cryptoConstants/cryptoConstants.type.js";
3
4
  import { PASSWORD_HASH } from "../cryptoConstants/cryptoConstants.security.js";
4
5
  import { assertPassword, validateParameters, } from "./cryptoPassword.validate.js";
@@ -13,6 +14,8 @@ import { assertNewHashCost } from "./cryptoPassword.helper.js";
13
14
  export async function hashPassword(password, options = {}) {
14
15
  assertPassword(password);
15
16
  const provider = options.provider ?? getDefaultCryptoProvider();
17
+ assertPasswordHashingCapability(provider);
18
+ assertRandomCapability(provider);
16
19
  const saltBytes = options.saltBytes ?? PASSWORD_HASH.SALT_BYTES;
17
20
  const keyBytes = options.keyBytes ?? PASSWORD_HASH.KEY_BYTES;
18
21
  const cost = options.cost ?? PASSWORD_HASH.SCRYPT.COST;
@@ -58,6 +61,7 @@ export async function hashPassword(password, options = {}) {
58
61
  * password also yields false.
59
62
  */
60
63
  export async function verifyPassword(password, encoded, provider = getDefaultCryptoProvider()) {
64
+ assertPasswordHashingCapability(provider);
61
65
  try {
62
66
  assertPassword(password);
63
67
  return await provider.verifyPassword(password, encoded);
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Capability checks for a crypto provider.
3
+ *
4
+ * `CryptoCapabilities` is required on every provider, but nothing read it:
5
+ * a provider declaring `signing: false` still had `sign` called, and a
6
+ * provider that only implements part of the interface only failed once the
7
+ * missing method was reached — as a bare `TypeError` from deep inside an
8
+ * unrelated operation. Both are checked here instead, so an unsupported
9
+ * operation is refused by name at the boundary.
10
+ *
11
+ * @module cryptoProvider/cryptoProvider.capability
12
+ */
13
+ import { CryptoOperation } from "@zudojs/errors";
14
+ import type { CryptoProvider } from "./cryptoProvider.core.js";
15
+ import type { CryptoCapabilities } from "./cryptoProvider.type.js";
16
+ /**
17
+ * Throws unless the provider declares the capability an operation needs.
18
+ *
19
+ * A missing or malformed `capabilities` object fails the same way a `false`
20
+ * flag does: a provider that cannot describe itself is not one a
21
+ * secret-handling path should call blind.
22
+ *
23
+ * @param provider - The provider about to be used.
24
+ * @param capability - The capability the operation requires.
25
+ * @param operation - The operation being attempted, for the error.
26
+ * @throws {CryptoError} when the capability is not declared.
27
+ */
28
+ export declare function assertProviderCapability(provider: CryptoProvider, capability: keyof CryptoCapabilities, operation: CryptoOperation): void;
29
+ /**
30
+ * Throws unless the provider declares `random`. @see assertProviderCapability
31
+ *
32
+ * Every helper that draws bytes — tokens, salts, ids, nonces — calls this, so
33
+ * the operation name is fixed in one place rather than at each call site.
34
+ */
35
+ export declare function assertRandomCapability(provider: CryptoProvider): void;
36
+ /** Throws unless the provider declares `hash`. @see assertProviderCapability */
37
+ export declare function assertHashCapability(provider: CryptoProvider): void;
38
+ /** Throws unless the provider declares `hmac`. @see assertProviderCapability */
39
+ export declare function assertHmacCapability(provider: CryptoProvider): void;
40
+ /**
41
+ * Throws unless the provider declares `passwordHashing`.
42
+ *
43
+ * `verifyPassword` answers `false` for anything wrong with the password, so a
44
+ * provider that cannot hash would read as "wrong password" forever. That is a
45
+ * configuration failure, and it throws.
46
+ */
47
+ export declare function assertPasswordHashingCapability(provider: CryptoProvider): void;
48
+ //# sourceMappingURL=cryptoProvider.capability.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Capability checks for a crypto provider.
3
+ *
4
+ * `CryptoCapabilities` is required on every provider, but nothing read it:
5
+ * a provider declaring `signing: false` still had `sign` called, and a
6
+ * provider that only implements part of the interface only failed once the
7
+ * missing method was reached — as a bare `TypeError` from deep inside an
8
+ * unrelated operation. Both are checked here instead, so an unsupported
9
+ * operation is refused by name at the boundary.
10
+ *
11
+ * @module cryptoProvider/cryptoProvider.capability
12
+ */
13
+ import { CryptoError, CryptoOperation, ErrorCode } from "@zudojs/errors";
14
+ /** The provider's reported name, without trusting it to be a string. */
15
+ function providerName(provider) {
16
+ return typeof provider.name === "string" && provider.name.length > 0
17
+ ? provider.name
18
+ : "unnamed";
19
+ }
20
+ /**
21
+ * Throws unless the provider declares the capability an operation needs.
22
+ *
23
+ * A missing or malformed `capabilities` object fails the same way a `false`
24
+ * flag does: a provider that cannot describe itself is not one a
25
+ * secret-handling path should call blind.
26
+ *
27
+ * @param provider - The provider about to be used.
28
+ * @param capability - The capability the operation requires.
29
+ * @param operation - The operation being attempted, for the error.
30
+ * @throws {CryptoError} when the capability is not declared.
31
+ */
32
+ export function assertProviderCapability(provider, capability, operation) {
33
+ const capabilities = provider.capabilities;
34
+ if (typeof capabilities !== "object" ||
35
+ capabilities === null ||
36
+ capabilities[capability] !== true) {
37
+ throw new CryptoError(`Crypto provider "${providerName(provider)}" does not support ` +
38
+ `${capability}: the "${operation}" operation was refused.`, { code: ErrorCode.CRYPTO, operation });
39
+ }
40
+ }
41
+ /**
42
+ * Throws unless the provider declares `random`. @see assertProviderCapability
43
+ *
44
+ * Every helper that draws bytes — tokens, salts, ids, nonces — calls this, so
45
+ * the operation name is fixed in one place rather than at each call site.
46
+ */
47
+ export function assertRandomCapability(provider) {
48
+ assertProviderCapability(provider, "random", CryptoOperation.RANDOM);
49
+ }
50
+ /** Throws unless the provider declares `hash`. @see assertProviderCapability */
51
+ export function assertHashCapability(provider) {
52
+ assertProviderCapability(provider, "hash", CryptoOperation.HASH);
53
+ }
54
+ /** Throws unless the provider declares `hmac`. @see assertProviderCapability */
55
+ export function assertHmacCapability(provider) {
56
+ assertProviderCapability(provider, "hmac", CryptoOperation.HASH);
57
+ }
58
+ /**
59
+ * Throws unless the provider declares `passwordHashing`.
60
+ *
61
+ * `verifyPassword` answers `false` for anything wrong with the password, so a
62
+ * provider that cannot hash would read as "wrong password" forever. That is a
63
+ * configuration failure, and it throws.
64
+ */
65
+ export function assertPasswordHashingCapability(provider) {
66
+ assertProviderCapability(provider, "passwordHashing", CryptoOperation.KEY_DERIVATION);
67
+ }
68
+ //# sourceMappingURL=cryptoProvider.capability.js.map
@@ -1,4 +1,18 @@
1
1
  import type { CryptoProvider } from "./cryptoProvider.core.js";
2
+ /** Every method a `CryptoProvider` must implement. */
3
+ export declare const CRYPTO_PROVIDER_METHODS: readonly ["randomBytes", "randomInt", "randomUUID", "hash", "hmac", "encrypt", "decrypt", "sign", "verify", "deriveKey", "hashPassword", "verifyPassword"];
4
+ /**
5
+ * Throws unless `provider` is a complete {@link CryptoProvider}.
6
+ *
7
+ * Installing `{}` as the process-wide default used to succeed and then fail
8
+ * at the first `randomHex(16)` with a `TypeError` — arbitrarily far from the
9
+ * call that caused it. Every method and every capability flag is checked
10
+ * here, at install time.
11
+ *
12
+ * @param provider - The candidate provider.
13
+ * @throws {CryptoError} when a method or a capability flag is missing.
14
+ */
15
+ export declare function assertCryptoProvider(provider: CryptoProvider): asserts provider is CryptoProvider;
2
16
  /**
3
17
  * Returns the process-wide default crypto provider, creating the Node
4
18
  * provider lazily on first use.
@@ -9,6 +23,13 @@ export declare function getDefaultCryptoProvider(): CryptoProvider;
9
23
  *
10
24
  * Every module-level helper (hash, encrypt, hashPassword, generateToken,
11
25
  * ...) that is not given an explicit provider uses this one.
26
+ *
27
+ * The provider is checked here rather than at first use: installing a partial
28
+ * object succeeded and then failed much later, inside whichever operation
29
+ * happened to reach the missing method first.
30
+ *
31
+ * @param provider - The provider to install process-wide.
32
+ * @throws {CryptoError} when a method or a capability flag is missing.
12
33
  */
13
34
  export declare function setDefaultCryptoProvider(provider: CryptoProvider): void;
14
35
  /**
@@ -1,4 +1,60 @@
1
+ import { CryptoError, CryptoOperation, ErrorCode } from "@zudojs/errors";
1
2
  import { createNodeCryptoProvider } from "../node/nodeCryptoProvider/nodeCryptoProvider.factory.js";
3
+ /** Every method a `CryptoProvider` must implement. */
4
+ export const CRYPTO_PROVIDER_METHODS = Object.freeze([
5
+ "randomBytes",
6
+ "randomInt",
7
+ "randomUUID",
8
+ "hash",
9
+ "hmac",
10
+ "encrypt",
11
+ "decrypt",
12
+ "sign",
13
+ "verify",
14
+ "deriveKey",
15
+ "hashPassword",
16
+ "verifyPassword",
17
+ ]);
18
+ /** Every capability flag a `CryptoProvider` must declare. */
19
+ const CRYPTO_CAPABILITY_FLAGS = Object.freeze([
20
+ "hash",
21
+ "hmac",
22
+ "encryption",
23
+ "signing",
24
+ "random",
25
+ "passwordHashing",
26
+ "keyDerivation",
27
+ ]);
28
+ /**
29
+ * Throws unless `provider` is a complete {@link CryptoProvider}.
30
+ *
31
+ * Installing `{}` as the process-wide default used to succeed and then fail
32
+ * at the first `randomHex(16)` with a `TypeError` — arbitrarily far from the
33
+ * call that caused it. Every method and every capability flag is checked
34
+ * here, at install time.
35
+ *
36
+ * @param provider - The candidate provider.
37
+ * @throws {CryptoError} when a method or a capability flag is missing.
38
+ */
39
+ export function assertCryptoProvider(provider) {
40
+ const candidate = provider;
41
+ for (const method of CRYPTO_PROVIDER_METHODS) {
42
+ if (typeof candidate[method] !== "function") {
43
+ throw new CryptoError(`Crypto provider is missing the "${method}" method: a provider must ` +
44
+ `implement all ${CRYPTO_PROVIDER_METHODS.length} operations.`, { code: ErrorCode.CRYPTO, operation: CryptoOperation.UNKNOWN });
45
+ }
46
+ }
47
+ const capabilities = candidate.capabilities;
48
+ if (typeof capabilities !== "object" || capabilities === null) {
49
+ throw new CryptoError("Crypto provider is missing its `capabilities` declaration.", { code: ErrorCode.CRYPTO, operation: CryptoOperation.UNKNOWN });
50
+ }
51
+ const flags = capabilities;
52
+ for (const flag of CRYPTO_CAPABILITY_FLAGS) {
53
+ if (typeof flags[flag] !== "boolean") {
54
+ throw new CryptoError(`Crypto provider capability "${flag}" must be a boolean.`, { code: ErrorCode.CRYPTO, operation: CryptoOperation.UNKNOWN });
55
+ }
56
+ }
57
+ }
2
58
  let defaultProvider;
3
59
  /**
4
60
  * Returns the process-wide default crypto provider, creating the Node
@@ -15,11 +71,19 @@ export function getDefaultCryptoProvider() {
15
71
  *
16
72
  * Every module-level helper (hash, encrypt, hashPassword, generateToken,
17
73
  * ...) that is not given an explicit provider uses this one.
74
+ *
75
+ * The provider is checked here rather than at first use: installing a partial
76
+ * object succeeded and then failed much later, inside whichever operation
77
+ * happened to reach the missing method first.
78
+ *
79
+ * @param provider - The provider to install process-wide.
80
+ * @throws {CryptoError} when a method or a capability flag is missing.
18
81
  */
19
82
  export function setDefaultCryptoProvider(provider) {
20
83
  if (typeof provider !== "object" || provider === null) {
21
84
  throw new TypeError("Crypto provider must be an object.");
22
85
  }
86
+ assertCryptoProvider(provider);
23
87
  defaultProvider = provider;
24
88
  }
25
89
  /**
@@ -10,6 +10,7 @@ export type { CryptoProvider } from "./cryptoProvider.core.js";
10
10
  export type { CryptoCapabilities, HashAlgorithm, HmacAlgorithm, Pbkdf2Digest, EncryptionAlgorithm, SignatureAlgorithm, KeyDerivationAlgorithm, EncodingFormat, CryptoInput, } from "./cryptoProvider.type.js";
11
11
  export { isHashAlgorithmName, isHmacAlgorithmName, isPbkdf2Digest, isSignatureAlgorithmName, } from "./cryptoProvider.type.js";
12
12
  export type { RandomProvider, HashProvider, HmacProvider, EncryptionProvider, SigningProvider, KeyDerivationProvider, PasswordProvider, } from "./cryptoProvider.interface.js";
13
- export { getDefaultCryptoProvider, setDefaultCryptoProvider, resetDefaultCryptoProvider, } from "./cryptoProvider.default.js";
13
+ export { getDefaultCryptoProvider, setDefaultCryptoProvider, resetDefaultCryptoProvider, assertCryptoProvider, CRYPTO_PROVIDER_METHODS, } from "./cryptoProvider.default.js";
14
+ export { assertProviderCapability, assertRandomCapability, assertHashCapability, assertHmacCapability, assertPasswordHashingCapability, } from "./cryptoProvider.capability.js";
14
15
  export * from "./types/index.js";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,5 @@
1
1
  export { isHashAlgorithmName, isHmacAlgorithmName, isPbkdf2Digest, isSignatureAlgorithmName, } from "./cryptoProvider.type.js";
2
- export { getDefaultCryptoProvider, setDefaultCryptoProvider, resetDefaultCryptoProvider, } from "./cryptoProvider.default.js";
2
+ export { getDefaultCryptoProvider, setDefaultCryptoProvider, resetDefaultCryptoProvider, assertCryptoProvider, CRYPTO_PROVIDER_METHODS, } from "./cryptoProvider.default.js";
3
+ export { assertProviderCapability, assertRandomCapability, assertHashCapability, assertHmacCapability, assertPasswordHashingCapability, } from "./cryptoProvider.capability.js";
3
4
  export * from "./types/index.js";
4
5
  //# sourceMappingURL=index.js.map
@@ -1,8 +1,10 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  /**
3
4
  * Generates a cryptographically secure random boolean.
4
5
  */
5
6
  export async function randomBoolean(provider = getDefaultCryptoProvider()) {
7
+ assertRandomCapability(provider);
6
8
  return (await provider.randomInt(0, 2)) === 1;
7
9
  }
8
10
  /**
@@ -11,6 +13,7 @@ export async function randomBoolean(provider = getDefaultCryptoProvider()) {
11
13
  * A single-element collection returns that element.
12
14
  */
13
15
  export async function randomChoice(values, provider = getDefaultCryptoProvider()) {
16
+ assertRandomCapability(provider);
14
17
  if (!Array.isArray(values) || values.length === 0) {
15
18
  throw new RangeError("Cannot choose from an empty collection.");
16
19
  }
@@ -21,6 +24,7 @@ export async function randomChoice(values, provider = getDefaultCryptoProvider()
21
24
  * random bytes.
22
25
  */
23
26
  export async function fillRandomBytes(target, provider = getDefaultCryptoProvider()) {
27
+ assertRandomCapability(provider);
24
28
  if (!(target instanceof Uint8Array)) {
25
29
  throw new TypeError("target must be a Uint8Array.");
26
30
  }
@@ -1,8 +1,10 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  /**
3
4
  * Generates cryptographically secure random bytes.
4
5
  */
5
6
  export async function randomBytesSecure(length, provider = getDefaultCryptoProvider()) {
7
+ assertRandomCapability(provider);
6
8
  return provider.randomBytes(length);
7
9
  }
8
10
  /**
@@ -14,6 +16,7 @@ export async function randomBytesSecure(length, provider = getDefaultCryptoProvi
14
16
  * Ranges up to 2^48 are supported; a range of one value returns `min`.
15
17
  */
16
18
  export async function randomInteger(min, max, provider = getDefaultCryptoProvider()) {
19
+ assertRandomCapability(provider);
17
20
  return provider.randomInt(min, max);
18
21
  }
19
22
  /**
@@ -21,12 +24,14 @@ export async function randomInteger(min, max, provider = getDefaultCryptoProvide
21
24
  * from zero up to, but excluding, max.
22
25
  */
23
26
  export async function randomIntegerBelow(max, provider = getDefaultCryptoProvider()) {
27
+ assertRandomCapability(provider);
24
28
  return provider.randomInt(0, max);
25
29
  }
26
30
  /**
27
31
  * Generates a random UUID v4.
28
32
  */
29
33
  export async function randomUuid(provider = getDefaultCryptoProvider()) {
34
+ assertRandomCapability(provider);
30
35
  return provider.randomUUID();
31
36
  }
32
37
  //# sourceMappingURL=cryptoRandom.core.js.map
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  function assertLength(length, name = "length") {
3
4
  if (!Number.isInteger(length) || length <= 0) {
4
5
  throw new RangeError(`${name} must be a positive integer.`);
@@ -9,6 +10,7 @@ function assertLength(length, name = "length") {
9
10
  */
10
11
  export async function randomHex(length, provider = getDefaultCryptoProvider()) {
11
12
  assertLength(length);
13
+ assertRandomCapability(provider);
12
14
  const bytes = await provider.randomBytes(Math.ceil(length / 2));
13
15
  return Buffer.from(bytes).toString("hex").slice(0, length);
14
16
  }
@@ -17,6 +19,7 @@ export async function randomHex(length, provider = getDefaultCryptoProvider()) {
17
19
  */
18
20
  export async function randomBase64(byteLength, provider = getDefaultCryptoProvider()) {
19
21
  assertLength(byteLength, "byteLength");
22
+ assertRandomCapability(provider);
20
23
  const bytes = await provider.randomBytes(byteLength);
21
24
  return Buffer.from(bytes).toString("base64");
22
25
  }
@@ -25,6 +28,7 @@ export async function randomBase64(byteLength, provider = getDefaultCryptoProvid
25
28
  */
26
29
  export async function randomBase64Url(byteLength, provider = getDefaultCryptoProvider()) {
27
30
  assertLength(byteLength, "byteLength");
31
+ assertRandomCapability(provider);
28
32
  const bytes = await provider.randomBytes(byteLength);
29
33
  return Buffer.from(bytes).toString("base64url");
30
34
  }
@@ -59,6 +63,7 @@ export async function randomAlphanumeric(length, provider = getDefaultCryptoProv
59
63
  */
60
64
  export async function randomFromAlphabet(length, alphabet, provider = getDefaultCryptoProvider()) {
61
65
  assertLength(length);
66
+ assertRandomCapability(provider);
62
67
  if (typeof alphabet !== "string" || alphabet.length === 0) {
63
68
  throw new RangeError("alphabet must not be empty.");
64
69
  }
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { generateCryptoKey, defaultKeyLength, } from "../cryptoKey/cryptoKey.factory.js";
3
4
  import { CryptoAlgorithm } from "../cryptoConstants/cryptoConstants.type.js";
4
5
  import { CryptoOperation } from "@zudojs/errors";
@@ -52,6 +53,7 @@ export class CryptoService {
52
53
  if (!Number.isInteger(length) || length <= 0) {
53
54
  throw new TypeError("Random byte length must be a positive integer.");
54
55
  }
56
+ assertRandomCapability(this.provider);
55
57
  try {
56
58
  return await this.provider.randomBytes(length);
57
59
  }
@@ -1,7 +1,9 @@
1
1
  import { getDefaultCryptoProvider } from "../../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertHashCapability } from "../../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { encode } from "../../cryptoEncoding/cryptoEncoding.core.js";
3
4
  import { hashError, rethrowAsCryptoError, } from "../../cryptoErrors/cryptoErrors.helper.js";
4
5
  export async function serviceHash(value, provider = getDefaultCryptoProvider()) {
6
+ assertHashCapability(provider);
5
7
  try {
6
8
  return await provider.hash("sha256", value);
7
9
  }
@@ -1,9 +1,12 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { CryptoOperation } from "@zudojs/errors";
3
+ import { assertProviderCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
4
  /**
3
5
  * Signs arbitrary data using a private key (PEM text, DER bytes or KeyObject).
4
6
  */
5
7
  export async function sign(data, privateKey, options = {}) {
6
8
  const provider = options.provider ?? getDefaultCryptoProvider();
9
+ assertProviderCapability(provider, "signing", CryptoOperation.SIGN);
7
10
  return provider.sign({
8
11
  key: privateKey,
9
12
  data,
@@ -18,6 +21,7 @@ export async function sign(data, privateKey, options = {}) {
18
21
  */
19
22
  export async function verify(data, signature, publicKey, options = {}) {
20
23
  const provider = options.provider ?? getDefaultCryptoProvider();
24
+ assertProviderCapability(provider, "signing", CryptoOperation.VERIFY_SIGNATURE);
21
25
  return provider.verify({
22
26
  key: publicKey,
23
27
  data,
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertRandomCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { randomInteger } from "../cryptoRandom/cryptoRandom.core.js";
3
4
  import { assertBinaryEncoding } from "../cryptoEncoding/cryptoEncoding.core.js";
4
5
  import { RANDOM, TOKEN, TOKEN_PREFIX, } from "../cryptoConstants/cryptoConstants.token.js";
@@ -20,6 +21,7 @@ export async function generateToken(options = {}) {
20
21
  throw new TypeError("Token prefix must be a string.");
21
22
  }
22
23
  const provider = options.provider ?? getDefaultCryptoProvider();
24
+ assertRandomCapability(provider);
23
25
  const raw = await provider.randomBytes(bytes);
24
26
  const token = Buffer.from(raw).toString(encoding);
25
27
  return options.prefix ? `${options.prefix}${token}` : token;
@@ -1,4 +1,5 @@
1
1
  import { getDefaultCryptoProvider } from "../cryptoProvider/cryptoProvider.default.js";
2
+ import { assertHashCapability } from "../cryptoProvider/cryptoProvider.capability.js";
2
3
  import { encode } from "../cryptoEncoding/cryptoEncoding.core.js";
3
4
  import { isHex } from "../cryptoEncoding/encoding/cryptoEncoding.hex.js";
4
5
  import { timingSafeEqual } from "../compare/compare.helper.js";
@@ -9,6 +10,7 @@ import { timingSafeEqual } from "../compare/compare.helper.js";
9
10
  */
10
11
  export async function hashToken(token, provider = getDefaultCryptoProvider()) {
11
12
  assertToken(token);
13
+ assertHashCapability(provider);
12
14
  const digest = await provider.hash("sha256", token);
13
15
  return encode(digest, "hex");
14
16
  }
@@ -17,6 +19,7 @@ export async function hashToken(token, provider = getDefaultCryptoProvider()) {
17
19
  */
18
20
  export async function hashTokenBase64Url(token, provider = getDefaultCryptoProvider()) {
19
21
  assertToken(token);
22
+ assertHashCapability(provider);
20
23
  const digest = await provider.hash("sha256", token);
21
24
  return encode(digest, "base64url");
22
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/crypto",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Cryptographic primitives for hashing, encryption, tokens, and secure random generation.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,8 +23,8 @@
23
23
  "node": ">=24.0.0"
24
24
  },
25
25
  "dependencies": {
26
- "@zudojs/constants": "1.1.0",
27
- "@zudojs/errors": "1.1.0"
26
+ "@zudojs/constants": "1.1.2",
27
+ "@zudojs/errors": "1.3.0"
28
28
  },
29
29
  "license": "MIT",
30
30
  "author": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "typescript": "7.0.2",
36
- "vitest": "^4.1.11"
36
+ "vitest": "^5.0.1"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
@@ -45,7 +45,7 @@
45
45
  "hashing",
46
46
  "security"
47
47
  ],
48
- "homepage": "https://github.com/oyinlola-tech/zudo#readme",
48
+ "homepage": "https://zudojs.oyinlola.site/docs/packages-crypto",
49
49
  "bugs": {
50
50
  "url": "https://github.com/oyinlola-tech/zudo/issues"
51
51
  },