@aura-stack/jose 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,35 +15,34 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
23
+ MIN_SECRET_ENTROPY_BITS: () => MIN_SECRET_ENTROPY_BITS,
33
24
  createDeriveKey: () => createDeriveKey,
34
25
  createJWE: () => createJWE,
35
26
  createJWS: () => createJWS,
36
27
  createJWT: () => createJWT,
28
+ createSecret: () => createSecret,
37
29
  decodeJWT: () => decodeJWT,
30
+ decoder: () => decoder,
38
31
  decryptJWE: () => decryptJWE,
39
32
  deriveKey: () => deriveKey,
40
33
  encodeJWT: () => encodeJWT,
34
+ encoder: () => encoder,
41
35
  encryptJWE: () => encryptJWE,
36
+ getEntropy: () => getEntropy,
37
+ getRandomBytes: () => getRandomBytes,
38
+ getSecrets: () => getSecrets,
39
+ getSubtleCrypto: () => getSubtleCrypto,
42
40
  signJWS: () => signJWS,
43
41
  verifyJWS: () => verifyJWS
44
42
  });
45
43
  module.exports = __toCommonJS(index_exports);
46
44
 
47
45
  // src/sign.ts
48
- var import_node_crypto = __toESM(require("crypto"), 1);
49
46
  var import_jose = require("jose");
50
47
 
51
48
  // src/errors.ts
@@ -83,6 +80,9 @@ var JWEEncryptionError = class extends AuraJoseError {
83
80
  var InvalidSecretError = class extends AuraJoseError {
84
81
  static code = "ERR_INVALID_SECRET";
85
82
  };
83
+ var KeyDerivationError = class extends AuraJoseError {
84
+ static code = "ERR_KEY_DERIVATION";
85
+ };
86
86
 
87
87
  // src/assert.ts
88
88
  var isAuraJoseError = (error) => {
@@ -98,16 +98,60 @@ var isInvalidPayload = (payload) => {
98
98
  return isFalsy(payload) || !isObject(payload) || typeof payload === "object" && payload !== null && !Array.isArray(payload) && Object.keys(payload).length === 0;
99
99
  };
100
100
 
101
+ // src/crypto.ts
102
+ var encoder = new TextEncoder();
103
+ var decoder = new TextDecoder();
104
+ var getRandomBytes = (size) => {
105
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
106
+ };
107
+ var getSubtleCrypto = () => {
108
+ if (globalThis.crypto?.subtle) {
109
+ return globalThis.crypto.subtle;
110
+ }
111
+ throw new Error("SubtleCrypto is not available in this runtime");
112
+ };
113
+
101
114
  // src/secret.ts
102
- var createSecret = (secret) => {
103
- if (secret === void 0) throw new InvalidSecretError("Secret is required");
115
+ var MIN_SECRET_ENTROPY_BITS = 4.5;
116
+ var getEntropy = (secret) => {
117
+ const charFreq = /* @__PURE__ */ new Map();
118
+ for (const char of secret) {
119
+ if (!charFreq.has(char)) {
120
+ charFreq.set(char, 0);
121
+ }
122
+ charFreq.set(char, charFreq.get(char) + 1);
123
+ }
124
+ let entropy = 0;
125
+ const length = secret.length;
126
+ for (const freq of charFreq.values()) {
127
+ const p = freq / length;
128
+ entropy -= p * Math.log2(p);
129
+ }
130
+ return entropy;
131
+ };
132
+ var createSecret = (secret, length = 32) => {
133
+ if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
104
134
  if (typeof secret === "string") {
105
- if (new TextEncoder().encode(secret).byteLength < 32) {
106
- throw new InvalidSecretError("Secret string must be at least 32 characters long");
135
+ const encoded = encoder.encode(secret);
136
+ const byteLength = encoded.byteLength;
137
+ if (byteLength < length) {
138
+ throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
139
+ }
140
+ const entropy = getEntropy(secret);
141
+ if (entropy < MIN_SECRET_ENTROPY_BITS) {
142
+ throw new InvalidSecretError(
143
+ `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
144
+ );
107
145
  }
108
- return new Uint8Array(Buffer.from(secret, "utf-8"));
146
+ return encoded;
109
147
  }
110
- return secret;
148
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
149
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
150
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
151
+ }
152
+ return secret;
153
+ }
154
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
111
155
  };
112
156
  var getSecrets = (secret) => {
113
157
  const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
@@ -125,8 +169,8 @@ var signJWS = async (payload, secret) => {
125
169
  throw new InvalidPayloadError("The payload must be a non-empty object");
126
170
  }
127
171
  const secretKey = createSecret(secret);
128
- const jti = import_node_crypto.default.randomBytes(32).toString("base64url");
129
- return new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
172
+ const jti = import_jose.base64url.encode(getRandomBytes(32));
173
+ return await new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
130
174
  } catch (error) {
131
175
  if (isAuraJoseError(error)) {
132
176
  throw error;
@@ -157,7 +201,6 @@ var createJWS = (secret) => {
157
201
  };
158
202
 
159
203
  // src/encrypt.ts
160
- var import_node_crypto2 = __toESM(require("crypto"), 1);
161
204
  var import_jose2 = require("jose");
162
205
  var encryptJWE = async (payload, secret, options) => {
163
206
  try {
@@ -165,8 +208,8 @@ var encryptJWE = async (payload, secret, options) => {
165
208
  throw new InvalidPayloadError("The payload must be a non-empty string");
166
209
  }
167
210
  const secretKey = createSecret(secret);
168
- const jti = import_node_crypto2.default.randomBytes(32).toString("base64url");
169
- return new import_jose2.EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
211
+ const jti = import_jose2.base64url.encode(getRandomBytes(32));
212
+ return await new import_jose2.EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
170
213
  } catch (error) {
171
214
  if (isAuraJoseError(error)) {
172
215
  throw error;
@@ -197,22 +240,35 @@ var createJWE = (secret) => {
197
240
  };
198
241
 
199
242
  // src/deriveKey.ts
200
- var import_node_crypto3 = require("crypto");
201
- var deriveKey = (secret, salt, info, length = 32) => {
243
+ var deriveKey = async (secret, salt, info, length = 32) => {
202
244
  try {
203
- const key = (0, import_node_crypto3.hkdfSync)("SHA256", secret, salt, info, length);
204
- const derivedKey = Buffer.from(key);
205
- return {
206
- key,
207
- derivedKey
208
- };
245
+ const subtle = getSubtleCrypto();
246
+ const secretBuffer = secret.buffer.slice(secret.byteOffset, secret.byteOffset + secret.byteLength);
247
+ const baseKey = await subtle.importKey("raw", secretBuffer, "HKDF", false, ["deriveBits"]);
248
+ const saltBuffer = typeof salt === "string" ? encoder.encode(salt) : salt;
249
+ const infoBuffer = typeof info === "string" ? encoder.encode(info) : info;
250
+ const derivedBits = await subtle.deriveBits(
251
+ {
252
+ name: "HKDF",
253
+ hash: "SHA-256",
254
+ salt: saltBuffer,
255
+ info: infoBuffer
256
+ },
257
+ baseKey,
258
+ length << 3
259
+ );
260
+ return new Uint8Array(derivedBits);
209
261
  } catch (error) {
210
- throw new Error("Failed to create a derived key (HKDF)", { cause: error });
262
+ throw new KeyDerivationError("Failed to create a derived key (HKDF)", { cause: error });
211
263
  }
212
264
  };
213
- var createDeriveKey = (secret, salt, info, length = 32) => {
265
+ var createDeriveKey = async (secret, salt, info, length = 32) => {
214
266
  const secretKey = createSecret(secret);
215
- return deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
267
+ if (secretKey instanceof CryptoKey) {
268
+ throw new KeyDerivationError("Cannot derive key from CryptoKey. Use Uint8Array or string secret instead.");
269
+ }
270
+ const key = await deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
271
+ return key;
216
272
  };
217
273
 
218
274
  // src/index.ts
@@ -230,13 +286,13 @@ var encodeJWT = async (token, secret) => {
230
286
  throw new JWTEncodingError("JWT encoding failed", { cause: error });
231
287
  }
232
288
  };
233
- var decodeJWT = async (token, secret) => {
289
+ var decodeJWT = async (token, secret, options) => {
234
290
  try {
235
291
  const { jweSecret, jwsSecret } = getSecrets(secret);
236
292
  const { verifyJWS: verifyJWS2 } = createJWS(jwsSecret);
237
293
  const { decryptJWE: decryptJWE2 } = createJWE(jweSecret);
238
- const decrypted = await decryptJWE2(token);
239
- return await verifyJWS2(decrypted);
294
+ const decrypted = await decryptJWE2(token, options?.jwt);
295
+ return await verifyJWS2(decrypted, options?.jws);
240
296
  } catch (error) {
241
297
  if (isAuraJoseError(error)) {
242
298
  throw error;
@@ -246,21 +302,29 @@ var decodeJWT = async (token, secret) => {
246
302
  };
247
303
  var createJWT = (secret) => {
248
304
  return {
249
- encodeJWT: async (payload) => encodeJWT(payload, secret),
250
- decodeJWT: async (token) => decodeJWT(token, secret)
305
+ encodeJWT: async (payload) => await encodeJWT(payload, secret),
306
+ decodeJWT: async (token, options) => await decodeJWT(token, secret, options)
251
307
  };
252
308
  };
253
309
  // Annotate the CommonJS export names for ESM import in node:
254
310
  0 && (module.exports = {
311
+ MIN_SECRET_ENTROPY_BITS,
255
312
  createDeriveKey,
256
313
  createJWE,
257
314
  createJWS,
258
315
  createJWT,
316
+ createSecret,
259
317
  decodeJWT,
318
+ decoder,
260
319
  decryptJWE,
261
320
  deriveKey,
262
321
  encodeJWT,
322
+ encoder,
263
323
  encryptJWE,
324
+ getEntropy,
325
+ getRandomBytes,
326
+ getSecrets,
327
+ getSubtleCrypto,
264
328
  signJWS,
265
329
  verifyJWS
266
330
  });
package/dist/index.d.ts CHANGED
@@ -1,154 +1,3 @@
1
- import { KeyObject, BinaryLike } from 'node:crypto';
2
- import { JWTPayload, JWTVerifyOptions, JWTDecryptOptions } from 'jose';
3
1
  export { JWTDecryptOptions, JWTVerifyOptions } from 'jose';
4
-
5
- /**
6
- * Sign a standard JWT token with the following claims:
7
- * - alg: algorithm used to sign the JWT
8
- * - typ: type of the token
9
- * - iat: time at which the JWT was issued
10
- * - nbf: not before time of the JWT
11
- * - exp: expiration time of the JWT
12
- * - jti: unique identifier to avoid collisions
13
- *
14
- * @param payload - Payload data information to sign the JWT
15
- * @param secret - Secret key to sign the JWT (CryptoKey, KeyObject, string or Uint8Array)
16
- * @returns Signed JWT string
17
- */
18
- declare const signJWS: (payload: JWTPayload, secret: SecretInput) => Promise<string>;
19
- /**
20
- * Verify the integrity of a JWT token and return the payload if valid, rejecting
21
- * tokens that use the "none" algorithm to prevent unsecured tokens.
22
- *
23
- * @see https://datatracker.ietf.org/doc/html/rfc7519#section-6 Unsecured JWTs
24
- * @param token - JWT string to verify
25
- * @param secret - CryptoKey or KeyObject used to verify the JWT
26
- * @returns verify and return the payload of the JWT
27
- */
28
- declare const verifyJWS: (token: string, secret: SecretInput, options?: JWTVerifyOptions) => Promise<JWTPayload>;
29
- /**
30
- * Create a JWS (JSON Web Signature) signer and verifier. It implements the `signJWS`
31
- * and `verifyJWS` functions of the module.
32
- *
33
- * @param secret - Secret key used for signing and verifying the JWS
34
- * @returns signJWS and verifyJWS functions
35
- */
36
- declare const createJWS: (secret: SecretInput) => {
37
- signJWS: (payload: JWTPayload) => Promise<string>;
38
- verifyJWS: (payload: string, options?: JWTVerifyOptions) => Promise<JWTPayload>;
39
- };
40
-
41
- interface EncryptedPayload {
42
- payload: string;
43
- }
44
- interface EncryptOptions {
45
- nbf?: string | number | Date;
46
- exp?: string | number | Date;
47
- }
48
- /**
49
- * Encrypt a standard JWT token with the following claims:
50
- * - alg: algorithm used to encrypt the JWT
51
- * - enc: encryption method used
52
- * - typ: type of the token
53
- * - cty: content type of the token
54
- *
55
- * @param payload - Payload data information to encrypt the JWT
56
- * @param secret - Secret key to encrypt the JWT (CryptoKey, KeyObject, string or Uint8Array)
57
- * @returns Encrypted JWT string
58
- */
59
- declare const encryptJWE: (payload: string, secret: SecretInput, options?: EncryptOptions) => Promise<string>;
60
- /**
61
- * Decrypt a JWE token and return the payload if valid.
62
- *
63
- * @param token - Encrypted JWT string to decrypt
64
- * @param secret - Secret key to decrypt the JWT (CryptoKey, KeyObject, string or Uint8Array)
65
- * @returns Decrypted JWT payload string
66
- */
67
- declare const decryptJWE: (token: string, secret: SecretInput, options?: JWTDecryptOptions) => Promise<string>;
68
- /**
69
- * Creates a `JWE (JSON Web Encryption)` encrypter and decrypter. It implements the `encryptJWE`
70
- * and `decryptJWE` functions of the module.
71
- *
72
- * @param secret - Secret key used for encrypting and decrypting the JWE
73
- * @returns encryptJWE and decryptJWE functions
74
- */
75
- declare const createJWE: (secret: SecretInput) => {
76
- encryptJWE: (payload: string, options?: EncryptOptions) => Promise<string>;
77
- decryptJWE: (payload: string, options?: JWTDecryptOptions) => Promise<string>;
78
- };
79
-
80
- /**
81
- * @module @aura-stack/jose
82
- */
83
-
84
- type SecretInput = KeyObject | Uint8Array | string;
85
- type DerivedKeyInput = {
86
- jws: SecretInput;
87
- jwe: SecretInput;
88
- };
89
- /**
90
- * Encode a JWT signed and encrypted token. The token first signed using JWS
91
- * and then encrypted using JWE to ensure both integrity and confidentiality.
92
- * It implements the `signJWS` and `encryptJWE` functions of the module.
93
- *
94
- * Based on the RFC 7519 standard
95
- * - Official RFC: https://datatracker.ietf.org/doc/html/rfc7519
96
- * - Nested JWTs should be signed and then encrypted: https://datatracker.ietf.org/doc/html/rfc7519#section-5.2
97
- * - Ensuring the integrity and confidentiality of the claims: https://datatracker.ietf.org/doc/html/rfc7519#section-11.2
98
- *
99
- * @param token - Payload data to encode in the JWT
100
- * @param secret - Secret key used for both signing and encrypting the JWT
101
- * @returns Promise resolving to the signed and encrypted JWT string
102
- */
103
- declare const encodeJWT: (token: JWTPayload, secret: SecretInput | DerivedKeyInput) => Promise<string>;
104
- /**
105
- * Decode a JWT signed and encrypted token. The token is first decrypted using JWE
106
- * and then verified using JWS to ensure both confidentiality and integrity. It
107
- * implements the `decryptJWE` and `verifyJWS` functions of the module.
108
- *
109
- * Based on the RFC 7519 standard
110
- * - Official RFC: https://datatracker.ietf.org/doc/html/rfc7519
111
- * - Validating a JWT: https://datatracker.ietf.org/doc/html/rfc7519#section-7.2
112
- * @param token
113
- * @param secret
114
- * @returns
115
- */
116
- declare const decodeJWT: (token: string, secret: SecretInput | DerivedKeyInput) => Promise<JWTPayload>;
117
- /**
118
- * Create a JWT handler with encode and decode methods to `signJWS/encryptJWE` and `verifyJWS/decryptJWE`
119
- * JWT tokens. The JWTs are signed and verified using JWS and encrypted and decrypted using JWE. It
120
- * implements the `signJWS`, `verifyJWS`, `encryptJWE` and `decryptJWE` functions of the module.
121
- *
122
- * @param secret - Secret key used for signing, verifying, encrypting and decrypting the JWT
123
- * @returns JWT handler object with `signJWS/encryptJWE` and `verifyJWS/decryptJWE` methods
124
- */
125
- declare const createJWT: (secret: SecretInput | DerivedKeyInput) => {
126
- encodeJWT: (payload: JWTPayload) => Promise<string>;
127
- decodeJWT: (token: string) => Promise<JWTPayload>;
128
- };
129
-
130
- /**
131
- * Generate a derived key using HKDF (HMAC-based Extract-and-Expand Key Derivation Function)
132
- *
133
- * @param secret Value used as the input keying material
134
- * @param salt Cryptographic salt
135
- * @param info Context and application specific information
136
- * @param length Size of the derived key in bytes (default is 32 bytes)
137
- * @returns Derived key as Uint8Array and base64 encoded string
138
- */
139
- declare const deriveKey: (secret: SecretInput, salt: BinaryLike, info: string, length?: number) => {
140
- key: ArrayBuffer;
141
- derivedKey: Buffer<ArrayBuffer>;
142
- };
143
- /**
144
- * Create a derived key from a given secret.
145
- *
146
- * @param secret - The secret as a string or Uint8Array
147
- * @returns The secret in Uint8Array format
148
- */
149
- declare const createDeriveKey: (secret: SecretInput, salt?: BinaryLike, info?: string, length?: number) => {
150
- key: ArrayBuffer;
151
- derivedKey: Buffer<ArrayBuffer>;
152
- };
153
-
154
- export { type DerivedKeyInput, type EncryptOptions, type EncryptedPayload, type SecretInput, createDeriveKey, createJWE, createJWS, createJWT, decodeJWT, decryptJWE, deriveKey, encodeJWT, encryptJWE, signJWS, verifyJWS };
2
+ export { D as DecodedJWTPayloadOptions, h as DerivedKeyInput, E as EncryptOptions, a as EncryptedPayload, M as MIN_SECRET_ENTROPY_BITS, P as Prettify, S as SecretInput, T as TypedJWTPayload, i as createDeriveKey, c as createJWE, createJWS, j as createJWT, b as createSecret, k as decodeJWT, d as decryptJWE, l as deriveKey, m as encodeJWT, e as encryptJWE, g as getEntropy, f as getSecrets, signJWS, verifyJWS } from './sign.js';
3
+ export { decoder, encoder, getRandomBytes, getSubtleCrypto } from './crypto.js';
package/dist/index.js CHANGED
@@ -1,27 +1,36 @@
1
+ import {
2
+ createJWS,
3
+ signJWS,
4
+ verifyJWS
5
+ } from "./chunk-WXGX6PJ5.js";
1
6
  import {
2
7
  createDeriveKey,
3
8
  deriveKey
4
- } from "./chunk-K5BQTFSO.js";
9
+ } from "./chunk-OG4QRUXH.js";
5
10
  import {
6
11
  createJWE,
7
12
  decryptJWE,
8
13
  encryptJWE
9
- } from "./chunk-VPFE27PW.js";
10
- import {
11
- createJWS,
12
- signJWS,
13
- verifyJWS
14
- } from "./chunk-ZHDED44B.js";
14
+ } from "./chunk-Q2LAK6W2.js";
15
15
  import {
16
+ MIN_SECRET_ENTROPY_BITS,
17
+ createSecret,
18
+ getEntropy,
16
19
  getSecrets
17
- } from "./chunk-GXM4P5MQ.js";
20
+ } from "./chunk-FCUM7BTG.js";
18
21
  import {
19
22
  isAuraJoseError
20
- } from "./chunk-ZHFHDRQH.js";
23
+ } from "./chunk-MWFJ4CA5.js";
24
+ import {
25
+ decoder,
26
+ encoder,
27
+ getRandomBytes,
28
+ getSubtleCrypto
29
+ } from "./chunk-RQFUZSWH.js";
21
30
  import {
22
31
  JWTDecodingError,
23
32
  JWTEncodingError
24
- } from "./chunk-BMXFAB6Q.js";
33
+ } from "./chunk-NGBYHSRN.js";
25
34
 
26
35
  // src/index.ts
27
36
  var encodeJWT = async (token, secret) => {
@@ -38,13 +47,13 @@ var encodeJWT = async (token, secret) => {
38
47
  throw new JWTEncodingError("JWT encoding failed", { cause: error });
39
48
  }
40
49
  };
41
- var decodeJWT = async (token, secret) => {
50
+ var decodeJWT = async (token, secret, options) => {
42
51
  try {
43
52
  const { jweSecret, jwsSecret } = getSecrets(secret);
44
53
  const { verifyJWS: verifyJWS2 } = createJWS(jwsSecret);
45
54
  const { decryptJWE: decryptJWE2 } = createJWE(jweSecret);
46
- const decrypted = await decryptJWE2(token);
47
- return await verifyJWS2(decrypted);
55
+ const decrypted = await decryptJWE2(token, options?.jwt);
56
+ return await verifyJWS2(decrypted, options?.jws);
48
57
  } catch (error) {
49
58
  if (isAuraJoseError(error)) {
50
59
  throw error;
@@ -54,20 +63,28 @@ var decodeJWT = async (token, secret) => {
54
63
  };
55
64
  var createJWT = (secret) => {
56
65
  return {
57
- encodeJWT: async (payload) => encodeJWT(payload, secret),
58
- decodeJWT: async (token) => decodeJWT(token, secret)
66
+ encodeJWT: async (payload) => await encodeJWT(payload, secret),
67
+ decodeJWT: async (token, options) => await decodeJWT(token, secret, options)
59
68
  };
60
69
  };
61
70
  export {
71
+ MIN_SECRET_ENTROPY_BITS,
62
72
  createDeriveKey,
63
73
  createJWE,
64
74
  createJWS,
65
75
  createJWT,
76
+ createSecret,
66
77
  decodeJWT,
78
+ decoder,
67
79
  decryptJWE,
68
80
  deriveKey,
69
81
  encodeJWT,
82
+ encoder,
70
83
  encryptJWE,
84
+ getEntropy,
85
+ getRandomBytes,
86
+ getSecrets,
87
+ getSubtleCrypto,
71
88
  signJWS,
72
89
  verifyJWS
73
90
  };
package/dist/secret.cjs CHANGED
@@ -20,7 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/secret.ts
21
21
  var secret_exports = {};
22
22
  __export(secret_exports, {
23
+ MIN_SECRET_ENTROPY_BITS: () => MIN_SECRET_ENTROPY_BITS,
23
24
  createSecret: () => createSecret,
25
+ getEntropy: () => getEntropy,
24
26
  getSecrets: () => getSecrets
25
27
  });
26
28
  module.exports = __toCommonJS(secret_exports);
@@ -45,16 +47,51 @@ var isObject = (value) => {
45
47
  return typeof value === "object" && value !== null && !Array.isArray(value);
46
48
  };
47
49
 
50
+ // src/crypto.ts
51
+ var encoder = new TextEncoder();
52
+ var decoder = new TextDecoder();
53
+
48
54
  // src/secret.ts
49
- var createSecret = (secret) => {
50
- if (secret === void 0) throw new InvalidSecretError("Secret is required");
55
+ var MIN_SECRET_ENTROPY_BITS = 4.5;
56
+ var getEntropy = (secret) => {
57
+ const charFreq = /* @__PURE__ */ new Map();
58
+ for (const char of secret) {
59
+ if (!charFreq.has(char)) {
60
+ charFreq.set(char, 0);
61
+ }
62
+ charFreq.set(char, charFreq.get(char) + 1);
63
+ }
64
+ let entropy = 0;
65
+ const length = secret.length;
66
+ for (const freq of charFreq.values()) {
67
+ const p = freq / length;
68
+ entropy -= p * Math.log2(p);
69
+ }
70
+ return entropy;
71
+ };
72
+ var createSecret = (secret, length = 32) => {
73
+ if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
51
74
  if (typeof secret === "string") {
52
- if (new TextEncoder().encode(secret).byteLength < 32) {
53
- throw new InvalidSecretError("Secret string must be at least 32 characters long");
75
+ const encoded = encoder.encode(secret);
76
+ const byteLength = encoded.byteLength;
77
+ if (byteLength < length) {
78
+ throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
79
+ }
80
+ const entropy = getEntropy(secret);
81
+ if (entropy < MIN_SECRET_ENTROPY_BITS) {
82
+ throw new InvalidSecretError(
83
+ `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
84
+ );
85
+ }
86
+ return encoded;
87
+ }
88
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
89
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
90
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
54
91
  }
55
- return new Uint8Array(Buffer.from(secret, "utf-8"));
92
+ return secret;
56
93
  }
57
- return secret;
94
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
58
95
  };
59
96
  var getSecrets = (secret) => {
60
97
  const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
@@ -66,6 +103,8 @@ var getSecrets = (secret) => {
66
103
  };
67
104
  // Annotate the CommonJS export names for ESM import in node:
68
105
  0 && (module.exports = {
106
+ MIN_SECRET_ENTROPY_BITS,
69
107
  createSecret,
108
+ getEntropy,
70
109
  getSecrets
71
110
  });
package/dist/secret.d.ts CHANGED
@@ -1,18 +1,3 @@
1
- import * as crypto from 'crypto';
2
- import { SecretInput, DerivedKeyInput } from './index.js';
3
- import 'node:crypto';
1
+ export { M as MIN_SECRET_ENTROPY_BITS, b as createSecret, g as getEntropy, f as getSecrets } from './sign.js';
4
2
  import 'jose';
5
-
6
- /**
7
- * Create a secret in Uint8Array format
8
- *
9
- * @param secret - The secret as a string or Uint8Array
10
- * @returns The secret in Uint8Array format
11
- */
12
- declare const createSecret: (secret: SecretInput) => crypto.KeyObject | Uint8Array<ArrayBufferLike>;
13
- declare const getSecrets: (secret: SecretInput | DerivedKeyInput) => {
14
- jwsSecret: SecretInput;
15
- jweSecret: SecretInput;
16
- };
17
-
18
- export { createSecret, getSecrets };
3
+ import './crypto.js';
package/dist/secret.js CHANGED
@@ -1,10 +1,15 @@
1
1
  import {
2
+ MIN_SECRET_ENTROPY_BITS,
2
3
  createSecret,
4
+ getEntropy,
3
5
  getSecrets
4
- } from "./chunk-GXM4P5MQ.js";
5
- import "./chunk-ZHFHDRQH.js";
6
- import "./chunk-BMXFAB6Q.js";
6
+ } from "./chunk-FCUM7BTG.js";
7
+ import "./chunk-MWFJ4CA5.js";
8
+ import "./chunk-RQFUZSWH.js";
9
+ import "./chunk-NGBYHSRN.js";
7
10
  export {
11
+ MIN_SECRET_ENTROPY_BITS,
8
12
  createSecret,
13
+ getEntropy,
9
14
  getSecrets
10
15
  };