@sebastienrousseau/crypto-server 0.0.8 → 0.0.9

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 (80) hide show
  1. package/README.md +159 -56
  2. package/dist/@types/types.d.ts +1 -2
  3. package/dist/@types/types.d.ts.map +1 -1
  4. package/dist/config/auth-policy.d.ts +18 -0
  5. package/dist/config/auth-policy.d.ts.map +1 -1
  6. package/dist/config/auth-policy.js +109 -0
  7. package/dist/enterprise/metering.d.ts.map +1 -1
  8. package/dist/enterprise/metering.js +2 -4
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +1 -0
  11. package/dist/lib/auth.d.ts +4 -1
  12. package/dist/lib/auth.d.ts.map +1 -1
  13. package/dist/lib/auth.js +87 -40
  14. package/dist/lib/kdf-runner.d.ts +18 -0
  15. package/dist/lib/kdf-runner.d.ts.map +1 -0
  16. package/dist/lib/kdf-runner.js +27 -0
  17. package/dist/lib/key-store.d.ts +30 -0
  18. package/dist/lib/key-store.d.ts.map +1 -0
  19. package/dist/lib/key-store.js +126 -0
  20. package/dist/lib/problem.d.ts +66 -0
  21. package/dist/lib/problem.d.ts.map +1 -0
  22. package/dist/lib/problem.js +152 -0
  23. package/dist/routes/v1/decrypt.d.ts.map +1 -1
  24. package/dist/routes/v1/decrypt.js +20 -15
  25. package/dist/routes/v1/encrypt.d.ts.map +1 -1
  26. package/dist/routes/v1/encrypt.js +12 -13
  27. package/dist/routes/v1/generate.d.ts.map +1 -1
  28. package/dist/routes/v1/generate.js +22 -25
  29. package/dist/routes/v1/revoke.d.ts.map +1 -1
  30. package/dist/routes/v1/revoke.js +6 -11
  31. package/dist/routes/v1/verify.d.ts.map +1 -1
  32. package/dist/routes/v1/verify.js +6 -11
  33. package/dist/routes/v2/algorithms.js +1 -1
  34. package/dist/routes/v2/compliance.js +1 -1
  35. package/dist/routes/v2/encrypt.d.ts.map +1 -1
  36. package/dist/routes/v2/encrypt.js +1 -1
  37. package/dist/routes/v2/hash.d.ts.map +1 -1
  38. package/dist/routes/v2/hash.js +1 -1
  39. package/dist/routes/v2/kdf.d.ts +5 -0
  40. package/dist/routes/v2/kdf.d.ts.map +1 -1
  41. package/dist/routes/v2/kdf.js +27 -12
  42. package/dist/routes/v2/key-wrap.d.ts.map +1 -1
  43. package/dist/routes/v2/key-wrap.js +9 -3
  44. package/dist/routes/v2/keys.d.ts.map +1 -1
  45. package/dist/routes/v2/keys.js +39 -26
  46. package/dist/routes/v2/mac.d.ts.map +1 -1
  47. package/dist/routes/v2/mac.js +9 -3
  48. package/dist/routes/v2/multi-recipient.d.ts.map +1 -1
  49. package/dist/routes/v2/multi-recipient.js +12 -11
  50. package/dist/routes/v2/password-encrypt.d.ts.map +1 -1
  51. package/dist/routes/v2/password-encrypt.js +13 -46
  52. package/dist/routes/v2/password.d.ts +4 -0
  53. package/dist/routes/v2/password.d.ts.map +1 -1
  54. package/dist/routes/v2/password.js +28 -53
  55. package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -1
  56. package/dist/routes/v2/pq-hash-sign.js +30 -24
  57. package/dist/routes/v2/pq-sign.d.ts.map +1 -1
  58. package/dist/routes/v2/pq-sign.js +30 -24
  59. package/dist/routes/v2/pq.d.ts.map +1 -1
  60. package/dist/routes/v2/pq.js +57 -38
  61. package/dist/routes/v2/sealedbox.d.ts.map +1 -1
  62. package/dist/routes/v2/sealedbox.js +32 -14
  63. package/dist/routes/v2/secretbox.d.ts.map +1 -1
  64. package/dist/routes/v2/secretbox.js +10 -3
  65. package/dist/routes/v2/signing.d.ts.map +1 -1
  66. package/dist/routes/v2/signing.js +16 -13
  67. package/dist/routes/v2/stream.d.ts.map +1 -1
  68. package/dist/routes/v2/stream.js +29 -24
  69. package/dist/server.d.ts.map +1 -1
  70. package/dist/server.js +15 -5
  71. package/dist/utils/keys.d.ts +17 -0
  72. package/dist/utils/keys.d.ts.map +1 -0
  73. package/dist/utils/keys.js +36 -0
  74. package/dist/utils/route-helpers.d.ts +1 -5
  75. package/dist/utils/route-helpers.d.ts.map +1 -1
  76. package/dist/utils/route-helpers.js +16 -10
  77. package/dist/utils/validation.d.ts +1 -0
  78. package/dist/utils/validation.d.ts.map +1 -1
  79. package/dist/utils/validation.js +17 -9
  80. package/package.json +20 -17
package/README.md CHANGED
@@ -159,46 +159,113 @@ All v2 endpoints accept and return `application/json`. Authenticated
159
159
  requests must include an `x-api-key` header (or
160
160
  `Authorization: Bearer <jwt>`).
161
161
 
162
- | Method | Path | Description |
163
- | :----- | :---------------------------- | :----------------------------------------------------------- |
164
- | `POST` | `/v2/hash` | Compute a cryptographic hash (SHA-2, SHA-3, BLAKE2b, BLAKE3) |
165
- | `POST` | `/v2/encrypt` | AEAD encryption with XChaCha20-Poly1305 |
166
- | `POST` | `/v2/decrypt` | AEAD decryption with XChaCha20-Poly1305 |
167
- | `POST` | `/v2/sign` | Create a digital signature |
168
- | `POST` | `/v2/verify` | Verify a digital signature |
169
- | `POST` | `/v2/kdf` | Derive a key (scrypt, HKDF-SHA256, PBKDF2-SHA256) |
170
- | `POST` | `/v2/hmac` | Compute an HMAC |
171
- | `POST` | `/v2/hmac/verify` | Verify an HMAC in constant time |
172
- | `POST` | `/v2/password/hash` | Hash a password with Argon2id |
173
- | `POST` | `/v2/password/verify` | Verify a password against an Argon2id hash |
174
- | `POST` | `/v2/password/encrypt` | Encrypt with password (Argon2id + XChaCha20-Poly1305) |
175
- | `POST` | `/v2/password/decrypt` | Decrypt with password |
176
- | `POST` | `/v2/keys/generate` | Generate a key pair for any supported algorithm |
177
- | `POST` | `/v2/keys/wrap` | Wrap a key with AES-KW or AES-KWP |
178
- | `POST` | `/v2/keys/unwrap` | Unwrap a key |
179
- | `POST` | `/v2/secretbox/seal` | Encrypt with XChaCha20-Poly1305 (secretbox) |
180
- | `POST` | `/v2/secretbox/open` | Decrypt a secretbox ciphertext |
181
- | `POST` | `/v2/sealedbox/seal` | Anonymous public-key encryption (X25519) |
182
- | `POST` | `/v2/sealedbox/open` | Decrypt an anonymous sealed box |
183
- | `POST` | `/v2/sealedbox/seal-pq` | Post-quantum sealed box (X25519 + ML-KEM-768) |
184
- | `POST` | `/v2/sealedbox/open-pq` | Decrypt a post-quantum sealed box |
185
- | `POST` | `/v2/multi-recipient/encrypt` | Encrypt for multiple recipients |
186
- | `POST` | `/v2/pq/keygen` | Generate an ML-KEM-768 key pair (FIPS 203) |
187
- | `POST` | `/v2/pq/encapsulate` | Encapsulate a shared secret with ML-KEM-768 |
188
- | `POST` | `/v2/pq/decapsulate` | Decapsulate and recover the shared secret |
189
- | `POST` | `/v2/pq/hybrid/keygen` | Generate a hybrid X25519 + ML-KEM-768 key pair |
190
- | `POST` | `/v2/pq/hybrid/encapsulate` | Hybrid encapsulation |
191
- | `POST` | `/v2/pq/hybrid/decapsulate` | Hybrid decapsulation |
192
- | `POST` | `/v2/pq/dsa/keygen` | Generate an ML-DSA key pair (FIPS 204) |
193
- | `POST` | `/v2/pq/dsa/sign` | Sign with ML-DSA |
194
- | `POST` | `/v2/pq/dsa/verify` | Verify an ML-DSA signature |
195
- | `POST` | `/v2/pq/slh-dsa/keygen` | Generate an SLH-DSA key pair (FIPS 205) |
196
- | `POST` | `/v2/pq/slh-dsa/sign` | Sign with SLH-DSA |
197
- | `POST` | `/v2/pq/slh-dsa/verify` | Verify an SLH-DSA signature |
198
- | `GET` | `/v2/algorithms` | List all supported algorithms |
199
- | `GET` | `/live` | Liveness probe (Kubernetes) |
200
- | `GET` | `/ready` | Readiness probe (Kubernetes) |
201
- | `GET` | `/metrics` | Prometheus-compatible metrics |
162
+ | Method | Path | Description |
163
+ | :----- | :---------------------------- | :------------------------------------------------------------------- |
164
+ | `POST` | `/v2/hash` | Compute a cryptographic hash (SHA-2, SHA-3, BLAKE2b, BLAKE3) |
165
+ | `POST` | `/v2/encrypt` | AEAD encryption with XChaCha20-Poly1305 |
166
+ | `POST` | `/v2/decrypt` | AEAD decryption with XChaCha20-Poly1305 |
167
+ | `POST` | `/v2/sign` | Sign with a server-held Ed25519 key (`keyId`) |
168
+ | `POST` | `/v2/verify` | Verify a digital signature |
169
+ | `POST` | `/v2/kdf` | Derive a key (scrypt N=2^17 r=8, HKDF-SHA256, PBKDF2-SHA256 >= 600k) |
170
+ | `POST` | `/v2/hmac` | Compute an HMAC |
171
+ | `POST` | `/v2/hmac/verify` | Verify an HMAC in constant time |
172
+ | `POST` | `/v2/password/hash` | Hash a password with Argon2id (m >= 19 MiB, t >= 2) |
173
+ | `POST` | `/v2/password/verify` | Verify a password against an Argon2id hash |
174
+ | `POST` | `/v2/password/encrypt` | Encrypt with password (Argon2id + XChaCha20-Poly1305) |
175
+ | `POST` | `/v2/password/decrypt` | Decrypt with password |
176
+ | `POST` | `/v2/keys/generate` | Generate a server-held key pair; returns `keyId` + public key |
177
+ | `POST` | `/v2/keys/export` | Export a private key (`crypto:keys:export` scope only) |
178
+ | `POST` | `/v2/keys/wrap` | Wrap a key with AES-KW or AES-KWP |
179
+ | `POST` | `/v2/keys/unwrap` | Unwrap a key |
180
+ | `POST` | `/v2/secretbox/seal` | Encrypt with XChaCha20-Poly1305 (secretbox) |
181
+ | `POST` | `/v2/secretbox/open` | Decrypt a secretbox ciphertext |
182
+ | `POST` | `/v2/sealedbox/seal` | Anonymous public-key encryption (X25519) |
183
+ | `POST` | `/v2/sealedbox/open` | Decrypt a sealed box with a server-held X25519 key (`keyId`) |
184
+ | `POST` | `/v2/sealedbox/seal-pq` | Post-quantum sealed box (X25519 + ML-KEM-768) |
185
+ | `POST` | `/v2/sealedbox/open-pq` | Decrypt a PQ sealed box with a server-held hybrid key |
186
+ | `POST` | `/v2/multi-recipient/encrypt` | Encrypt for multiple recipients |
187
+ | `POST` | `/v2/pq/keygen` | Generate an ML-KEM-768 key pair (FIPS 203) |
188
+ | `POST` | `/v2/pq/encapsulate` | Encapsulate a shared secret with ML-KEM-768 |
189
+ | `POST` | `/v2/pq/decapsulate` | Decapsulate with a server-held ML-KEM-768 key (`keyId`) |
190
+ | `POST` | `/v2/pq/hybrid/keygen` | Generate a hybrid X25519 + ML-KEM-768 key pair |
191
+ | `POST` | `/v2/pq/hybrid/encapsulate` | Hybrid encapsulation |
192
+ | `POST` | `/v2/pq/hybrid/decapsulate` | Hybrid decapsulation with a server-held key (`keyId`) |
193
+ | `POST` | `/v2/pq/dsa/keygen` | Generate an ML-DSA key pair (FIPS 204) |
194
+ | `POST` | `/v2/pq/dsa/sign` | Sign with a server-held ML-DSA key (`keyId`) |
195
+ | `POST` | `/v2/pq/dsa/verify` | Verify an ML-DSA signature |
196
+ | `POST` | `/v2/pq/slh-dsa/keygen` | Generate an SLH-DSA key pair (FIPS 205) |
197
+ | `POST` | `/v2/pq/slh-dsa/sign` | Sign with a server-held SLH-DSA key (`keyId`) |
198
+ | `POST` | `/v2/pq/slh-dsa/verify` | Verify an SLH-DSA signature |
199
+ | `GET` | `/v2/algorithms` | List all supported algorithms |
200
+ | `GET` | `/live` | Liveness probe (Kubernetes) |
201
+ | `GET` | `/ready` | Readiness probe (Kubernetes) |
202
+ | `GET` | `/metrics` | Prometheus-compatible metrics |
203
+
204
+ <p align="right"><a href="#contents">Back to Top</a></p>
205
+
206
+ ### Errors
207
+
208
+ Every error response is an RFC 9457 problem, served as
209
+ `application/problem+json`:
210
+
211
+ ```json
212
+ {
213
+ "type": "urn:crypto-service:problem:forbidden",
214
+ "title": "Forbidden",
215
+ "status": 403,
216
+ "detail": "Missing required scope: crypto:encrypt",
217
+ "instance": "/v2/encrypt"
218
+ }
219
+ ```
220
+
221
+ `type` is `urn:crypto-service:problem:<slug>`, one of
222
+ `validation-failed` (400, with an `errors` array of `{ field, message }`),
223
+ `invalid-input` (400), `request-error` (other 4xx), `unauthorized` (401),
224
+ `forbidden` (403), `not-found` (404), `key-not-found` (404),
225
+ `key-algorithm-mismatch` (400), `payload-too-large` (413),
226
+ `rate-limited` (429, with `Retry-After`), `key-store-full` (503) and
227
+ `internal-error` (500). A crypto-lib `CryptoError` or key-store error
228
+ adds its `code`. A 500 never carries the internal message or stack, and
229
+ `instance` is the request path without its query string.
230
+
231
+ ### Work factors
232
+
233
+ `/v2/kdf` and `/v2/password/hash` enforce the OWASP Password Storage
234
+ Cheat Sheet floors for new keys and hashes: scrypt N = 2^17 with r = 8
235
+ (crypto-lib caps N at 2^17), PBKDF2-HMAC-SHA256 with at least 600,000
236
+ iterations, and Argon2id with at least 19 MiB of memory and two passes.
237
+ A lower value gets `400`. `/v2/password/verify` still accepts the
238
+ parameters of existing hashes. Scrypt, PBKDF2 and Argon2 (including
239
+ `/v2/password/encrypt` and `/decrypt`) run on two worker threads, so a
240
+ derivation does not block other requests or the health probes; further
241
+ derivations queue.
242
+
243
+ ### Key custody
244
+
245
+ The API never takes a private key and never returns one, with one
246
+ exception below. Key-generation routes (`/v2/keys/generate`,
247
+ `/v2/pq/keygen`, `/v2/pq/hybrid/keygen`, `/v2/pq/dsa/keygen`,
248
+ `/v2/pq/slh-dsa/keygen`) keep the private key on the server and return
249
+ a `keyId` with the public key. Signing, sealed-box opening and
250
+ decapsulation routes take that `keyId`. A key belongs to the principal
251
+ (token `sub`) that generated it; for anyone else it does not exist
252
+ (`404`).
253
+
254
+ Keys live in memory (at most 10,000 without persistence). Set
255
+ `CRYPTO_KEY_OUT_DIR` to also write each key to `<keyId>.json` there
256
+ (mode `0600`, never overwritten) so keys survive a restart; those files
257
+ hold the private key unencrypted, so protect the directory.
258
+
259
+ `POST /v2/keys/export` returns a key's private parts. It needs the
260
+ `crypto:keys:export` scope, granted explicitly in a JWT: `crypto:admin`
261
+ does not include it, so API-key and anonymous principals cannot export.
262
+
263
+ The v1 routes use the server's own OpenPGP key pair from
264
+ `CRYPTO_KEY_DIR`: `/v1/decrypt` decrypts messages sent to it, and
265
+ `/v1/encrypt` signs with it when `sign` is `true`.
266
+
267
+ Symmetric keys (`/v2/encrypt`, `/v2/secretbox/*`, `/v2/hmac`, the
268
+ key-wrap KEK) are still supplied by the client.
202
269
 
203
270
  <p align="right"><a href="#contents">Back to Top</a></p>
204
271
 
@@ -211,8 +278,9 @@ The server supports two authentication modes:
211
278
  2. **JWT Bearer** -- set `JWT_SECRET` and pass
212
279
  `Authorization: Bearer <token>`.
213
280
 
214
- If neither variable is set, all requests are allowed (development
215
- mode).
281
+ If neither variable is set, every request except the probes and
282
+ `/docs` gets `401`, unless `ALLOW_ANONYMOUS=1` is set for local
283
+ development or behind an authenticating gateway.
216
284
 
217
285
  ```bash
218
286
  # API key
@@ -222,24 +290,59 @@ curl -H "x-api-key: your-secret-api-key" ...
222
290
  curl -H "Authorization: Bearer eyJhbGciOi..." ...
223
291
  ```
224
292
 
293
+ A JWT must be HS256 and carry `exp` and `iat`; it is refused once it
294
+ is older than `JWT_MAX_AGE` seconds (default 3600) or if it declares a
295
+ longer lifetime (`exp - iat`). When `JWT_ISSUER` / `JWT_AUDIENCE` are
296
+ set, its `iss` must equal the issuer and its `aud` must contain the
297
+ audience. In production (`NODE_ENV=production`) both are required
298
+ whenever `JWT_SECRET` is set, and the server refuses to start without
299
+ them.
300
+
301
+ ### Scopes
302
+
303
+ Every route requires one scope, defined in one table
304
+ (`ROUTE_SCOPES` in `src/config/auth-policy.ts`). A principal without it
305
+ gets `403`. The server refuses to start if a route has no entry.
306
+ JWT principals carry their scopes in a `scopes` array claim; API-key
307
+ and anonymous principals hold `crypto:admin`, which satisfies every
308
+ scope except `crypto:keys:export`.
309
+
310
+ | Scope | Routes |
311
+ | :------------------- | :------------------------------------------------------------------------------------------------------------------- |
312
+ | `crypto:encrypt` | `/v1/encrypt`, `/v2/encrypt`, secretbox/sealedbox seal, password and multi-recipient encrypt, PQ encapsulate |
313
+ | `crypto:decrypt` | `/v1/decrypt`, `/v2/decrypt`, secretbox/sealedbox open, password decrypt, PQ decapsulate |
314
+ | `crypto:sign` | `/v2/sign`, `/v2/stream/sign`, ML-DSA and SLH-DSA sign, `/v2/hmac` |
315
+ | `crypto:verify` | `/v1/verify`, `/v2/verify`, `/v2/stream/verify`, `/v2/stream/iso20022`, ML-DSA and SLH-DSA verify, `/v2/hmac/verify` |
316
+ | `crypto:hash` | `/v2/hash` |
317
+ | `crypto:kdf` | `/v2/kdf`, `/v2/password/hash`, `/v2/password/verify` |
318
+ | `crypto:keys` | `/v1/generate`, `/v2/keys/*`, PQ, ML-DSA and SLH-DSA keygen |
319
+ | `crypto:keys:export` | `/v2/keys/export`; never implied by `crypto:admin` |
320
+ | `crypto:admin` | `/v1/revoke` (revokes the server's own key pair); satisfies every other scope except `crypto:keys:export` |
321
+
322
+ `GET /`, `GET /v2/algorithms` and `GET /v2/compliance/*` need
323
+ authentication but no scope.
324
+
225
325
  <p align="right"><a href="#contents">Back to Top</a></p>
226
326
 
227
327
  ## Configuration
228
328
 
229
- | Variable | Default | Description |
230
- | :-------------------- | :------------ | :------------------------------------------------- |
231
- | `PORT` | `3000` | TCP port to listen on |
232
- | `HOST` | `localhost` | Bind address |
233
- | `PROTOCOL` | `http` | `http` or `https` |
234
- | `NODE_ENV` | `development` | `development`, `production`, or `test` |
235
- | `LOG_LEVEL` | `info` | `error`, `warn`, `info`, or `debug` |
236
- | `CRYPTO_API_KEY` | -- | Static API key for `x-api-key` authentication |
237
- | `JWT_SECRET` | -- | HMAC secret for HS256 JWT validation |
238
- | `CORS_ORIGIN` | -- | Comma-separated allowed origins (empty = disabled) |
239
- | `TRUSTED_PROXY_CIDRS` | -- | Comma-separated trusted proxy CIDRs |
240
- | `CRYPTO_KEY_DIR` | -- | Directory for key storage |
241
- | `CRYPTO_KEY_OUT_DIR` | -- | Directory for key output |
242
- | `SHUTDOWN_TIMEOUT_MS` | `30000` | Graceful shutdown timeout in milliseconds |
329
+ | Variable | Default | Description |
330
+ | :-------------------- | :------------ | :--------------------------------------------------- |
331
+ | `PORT` | `3000` | TCP port to listen on |
332
+ | `HOST` | `localhost` | Bind address |
333
+ | `PROTOCOL` | `http` | `http` or `https` |
334
+ | `NODE_ENV` | `development` | `development`, `production`, or `test` |
335
+ | `LOG_LEVEL` | `info` | `error`, `warn`, `info`, or `debug` |
336
+ | `CRYPTO_API_KEY` | -- | Static API key for `x-api-key` authentication |
337
+ | `JWT_SECRET` | -- | HMAC secret for HS256 JWT validation |
338
+ | `JWT_MAX_AGE` | `3600` | Maximum JWT lifetime in seconds |
339
+ | `JWT_ISSUER` | -- | Required JWT `iss` (required in production) |
340
+ | `JWT_AUDIENCE` | -- | Required JWT `aud` (required in production) |
341
+ | `CORS_ORIGIN` | -- | Comma-separated allowed origins (empty = disabled) |
342
+ | `TRUSTED_PROXY_CIDRS` | -- | Comma-separated trusted proxy CIDRs |
343
+ | `CRYPTO_KEY_DIR` | -- | Directory for key storage |
344
+ | `CRYPTO_KEY_OUT_DIR` | -- | Where generated keys are persisted (see Key custody) |
345
+ | `SHUTDOWN_TIMEOUT_MS` | `30000` | Graceful shutdown timeout in milliseconds |
243
346
 
244
347
  <p align="right"><a href="#contents">Back to Top</a></p>
245
348
 
@@ -20,13 +20,12 @@ export interface IBodyEncrypt {
20
20
  passphrase: string;
21
21
  message: string;
22
22
  publicKey: string;
23
- privateKey?: string;
23
+ sign?: boolean;
24
24
  }
25
25
  export interface IBodyDecrypt {
26
26
  passphrase: string;
27
27
  message: string;
28
28
  publicKey: string;
29
- privateKey: string;
30
29
  }
31
30
  export interface IBodyRevoke {
32
31
  passphrase: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/@types/types.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,SAAS,yBAA0B,CAAC;AAEjD,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjD,eAAO,MAAM,WAAW,kIAUd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAKrD,eAAO,MAAM,YAAY,0CAA2C,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAKvD,eAAO,MAAM,gBAAgB,uBAAwB,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAiB/D,MAAM,WAAW,aAAa;IAE5B,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,OAAO,CAAC;IAEd,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,SAAS,CAAC;IAEjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,MAAM,EAAE,UAAU,CAAC;CACpB;AAcD,MAAM,WAAW,YAAY;IAE3B,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD,MAAM,WAAW,YAAY;IAE3B,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,MAAM,CAAC;CACpB;AAcD,MAAM,WAAW,WAAW;IAE1B,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IAEb,MAAM,EAAE,MAAM,CAAC;CAChB;AAcD,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,MAAM,CAAC;IAEhB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/@types/types.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,SAAS,yBAA0B,CAAC;AAEjD,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjD,eAAO,MAAM,WAAW,kIAUd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAKrD,eAAO,MAAM,YAAY,0CAA2C,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAKvD,eAAO,MAAM,gBAAgB,uBAAwB,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAiB/D,MAAM,WAAW,aAAa;IAE5B,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,OAAO,CAAC;IAEd,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,SAAS,CAAC;IAEjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,MAAM,EAAE,UAAU,CAAC;CACpB;AAcD,MAAM,WAAW,YAAY;IAE3B,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,MAAM,WAAW,YAAY;IAE3B,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD,MAAM,WAAW,WAAW;IAE1B,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IAEb,MAAM,EAAE,MAAM,CAAC;CAChB;AAcD,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,MAAM,CAAC;IAEhB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
@@ -1,2 +1,20 @@
1
+ export declare const DEFAULT_JWT_MAX_AGE_SECONDS = 3600;
2
+ export interface JwtPolicy {
3
+ readonly maxAgeSeconds: number;
4
+ readonly issuer: string | undefined;
5
+ readonly audience: string | undefined;
6
+ }
7
+ export declare function jwtConfigError(env: NodeJS.ProcessEnv): string | null;
8
+ export declare function jwtPolicy(env: NodeJS.ProcessEnv): JwtPolicy;
1
9
  export declare function authConfigError(env: NodeJS.ProcessEnv): string | null;
10
+ export declare const AUTHENTICATED = "authenticated";
11
+ export declare const ROUTE_SCOPES: Readonly<Record<string, string>>;
12
+ export declare function isPublicRoute(url: string): boolean;
13
+ export declare function routeRequirement(method: string, url: string): string | undefined;
14
+ export interface RegisteredRoute {
15
+ method: string | string[];
16
+ url: string;
17
+ }
18
+ export declare function unmappedRoutes(routes: readonly RegisteredRoute[]): string[];
19
+ export declare function assertRoutesCovered(routes: readonly RegisteredRoute[]): void;
2
20
  //# sourceMappingURL=auth-policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-policy.d.ts","sourceRoot":"","sources":["../../src/config/auth-policy.ts"],"names":[],"mappings":"AAsBA,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,IAAI,CAcrE"}
1
+ {"version":3,"file":"auth-policy.d.ts","sourceRoot":"","sources":["../../src/config/auth-policy.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAGhD,MAAM,WAAW,SAAS;IAMxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAQD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,IAAI,CAUpE;AAMD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAO3D;AAUD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,IAAI,CAgBrE;AAOD,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAY7C,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6DxD,CAAC;AAMH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAMD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAGpB;AAGD,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,EAAE,CAY3E;AAOD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAO5E"}
@@ -1,12 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROUTE_SCOPES = exports.AUTHENTICATED = exports.DEFAULT_JWT_MAX_AGE_SECONDS = void 0;
4
+ exports.jwtConfigError = jwtConfigError;
5
+ exports.jwtPolicy = jwtPolicy;
3
6
  exports.authConfigError = authConfigError;
7
+ exports.isPublicRoute = isPublicRoute;
8
+ exports.routeRequirement = routeRequirement;
9
+ exports.unmappedRoutes = unmappedRoutes;
10
+ exports.assertRoutesCovered = assertRoutesCovered;
11
+ const constants_1 = require("./constants");
4
12
  const MIN_JWT_SECRET_BYTES = 32;
13
+ exports.DEFAULT_JWT_MAX_AGE_SECONDS = 3600;
14
+ function jwtConfigError(env) {
15
+ const maxAge = env["JWT_MAX_AGE"];
16
+ if (maxAge && !/^[1-9]\d{0,8}$/.test(maxAge)) {
17
+ return "JWT_MAX_AGE must be a positive integer number of seconds";
18
+ }
19
+ const pinned = Boolean(env["JWT_ISSUER"] && env["JWT_AUDIENCE"]);
20
+ if (env["NODE_ENV"] === "production" && env["JWT_SECRET"] && !pinned) {
21
+ return "Production with JWT_SECRET requires JWT_ISSUER and JWT_AUDIENCE";
22
+ }
23
+ return null;
24
+ }
25
+ function jwtPolicy(env) {
26
+ const maxAge = env["JWT_MAX_AGE"];
27
+ return {
28
+ maxAgeSeconds: maxAge ? Number(maxAge) : exports.DEFAULT_JWT_MAX_AGE_SECONDS,
29
+ issuer: env["JWT_ISSUER"] || undefined,
30
+ audience: env["JWT_AUDIENCE"] || undefined,
31
+ };
32
+ }
5
33
  function authConfigError(env) {
6
34
  const jwtSecret = env["JWT_SECRET"];
7
35
  if (jwtSecret && Buffer.byteLength(jwtSecret) < MIN_JWT_SECRET_BYTES) {
8
36
  return `JWT_SECRET must be at least ${MIN_JWT_SECRET_BYTES} bytes`;
9
37
  }
38
+ const jwtError = jwtConfigError(env);
39
+ if (jwtError)
40
+ return jwtError;
10
41
  const hasCredential = Boolean(env["CRYPTO_API_KEY"] || jwtSecret);
11
42
  if (env["NODE_ENV"] === "production" &&
12
43
  !hasCredential &&
@@ -15,4 +46,82 @@ function authConfigError(env) {
15
46
  }
16
47
  return null;
17
48
  }
49
+ exports.AUTHENTICATED = "authenticated";
50
+ exports.ROUTE_SCOPES = Object.freeze({
51
+ "GET /": exports.AUTHENTICATED,
52
+ "GET /v2/algorithms": exports.AUTHENTICATED,
53
+ "GET /v2/compliance/dora": exports.AUTHENTICATED,
54
+ "GET /v2/compliance/cbom": exports.AUTHENTICATED,
55
+ "OPTIONS *": exports.AUTHENTICATED,
56
+ "POST /v1/encrypt": "crypto:encrypt",
57
+ "POST /v1/decrypt": "crypto:decrypt",
58
+ "POST /v1/verify": "crypto:verify",
59
+ "POST /v1/generate": "crypto:keys",
60
+ "POST /v1/revoke": "crypto:admin",
61
+ "POST /v2/encrypt": "crypto:encrypt",
62
+ "POST /v2/secretbox/seal": "crypto:encrypt",
63
+ "POST /v2/sealedbox/seal": "crypto:encrypt",
64
+ "POST /v2/sealedbox/seal-pq": "crypto:encrypt",
65
+ "POST /v2/password/encrypt": "crypto:encrypt",
66
+ "POST /v2/multi-recipient/encrypt": "crypto:encrypt",
67
+ "POST /v2/pq/encapsulate": "crypto:encrypt",
68
+ "POST /v2/pq/hybrid/encapsulate": "crypto:encrypt",
69
+ "POST /v2/decrypt": "crypto:decrypt",
70
+ "POST /v2/secretbox/open": "crypto:decrypt",
71
+ "POST /v2/sealedbox/open": "crypto:decrypt",
72
+ "POST /v2/sealedbox/open-pq": "crypto:decrypt",
73
+ "POST /v2/password/decrypt": "crypto:decrypt",
74
+ "POST /v2/pq/decapsulate": "crypto:decrypt",
75
+ "POST /v2/pq/hybrid/decapsulate": "crypto:decrypt",
76
+ "POST /v2/sign": "crypto:sign",
77
+ "POST /v2/stream/sign": "crypto:sign",
78
+ "POST /v2/pq/dsa/sign": "crypto:sign",
79
+ "POST /v2/pq/slh-dsa/sign": "crypto:sign",
80
+ "POST /v2/hmac": "crypto:sign",
81
+ "POST /v2/verify": "crypto:verify",
82
+ "POST /v2/stream/verify": "crypto:verify",
83
+ "POST /v2/stream/iso20022": "crypto:verify",
84
+ "POST /v2/pq/dsa/verify": "crypto:verify",
85
+ "POST /v2/pq/slh-dsa/verify": "crypto:verify",
86
+ "POST /v2/hmac/verify": "crypto:verify",
87
+ "POST /v2/hash": "crypto:hash",
88
+ "POST /v2/kdf": "crypto:kdf",
89
+ "POST /v2/password/hash": "crypto:kdf",
90
+ "POST /v2/password/verify": "crypto:kdf",
91
+ "POST /v2/keys/generate": "crypto:keys",
92
+ "POST /v2/keys/export": "crypto:keys:export",
93
+ "POST /v2/keys/wrap": "crypto:keys",
94
+ "POST /v2/keys/unwrap": "crypto:keys",
95
+ "POST /v2/pq/keygen": "crypto:keys",
96
+ "POST /v2/pq/hybrid/keygen": "crypto:keys",
97
+ "POST /v2/pq/dsa/keygen": "crypto:keys",
98
+ "POST /v2/pq/slh-dsa/keygen": "crypto:keys",
99
+ });
100
+ function isPublicRoute(url) {
101
+ return (0, constants_1.isProbePath)(url) || url.startsWith("/docs");
102
+ }
103
+ function routeRequirement(method, url) {
104
+ const verb = method === "HEAD" ? "GET" : method;
105
+ return exports.ROUTE_SCOPES[`${verb} ${url}`];
106
+ }
107
+ function unmappedRoutes(routes) {
108
+ const missing = [];
109
+ for (const route of routes) {
110
+ if (isPublicRoute(route.url))
111
+ continue;
112
+ const methods = Array.isArray(route.method) ? route.method : [route.method];
113
+ for (const method of methods) {
114
+ if (routeRequirement(method, route.url) === undefined) {
115
+ missing.push(`${method} ${route.url}`);
116
+ }
117
+ }
118
+ }
119
+ return missing;
120
+ }
121
+ function assertRoutesCovered(routes) {
122
+ const missing = unmappedRoutes(routes);
123
+ if (missing.length > 0) {
124
+ throw new Error(`Routes without an authorization policy: ${missing.join(", ")}`);
125
+ }
126
+ }
18
127
  //# sourceMappingURL=auth-policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../../src/enterprise/metering.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,WAAW,EAEZ,MAAM,SAAS,CAAC;AAWjB,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,CAsBxD,CAAC;AAGF,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAY1C,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAIvC,UAAU,GAAE,MAA4B;IAI3D,IAAW,IAAI,IAAI,MAAM,CAExB;IASM,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW;IAOhD,OAAO,CAAC,QAAQ;IAwBhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IAqBb,YAAY,CACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,WAAW,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,KAAK,GAAE,MAAmB,GACzB,mBAAmB;IA4Df,KAAK,IAAI,IAAI;CAGrB;AAGD,eAAO,MAAM,qBAAqB,gBAAuB,CAAC;AA6B1D,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAQ,cAAqC,KAC5C,IAgCF,CAAC"}
1
+ {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../../src/enterprise/metering.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAG7E,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,WAAW,EAEZ,MAAM,SAAS,CAAC;AAWjB,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,CAsBxD,CAAC;AAGF,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAY1C,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAIvC,UAAU,GAAE,MAA4B;IAI3D,IAAW,IAAI,IAAI,MAAM,CAExB;IASM,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW;IAOhD,OAAO,CAAC,QAAQ;IAwBhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IAqBb,YAAY,CACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,WAAW,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,KAAK,GAAE,MAAmB,GACzB,mBAAmB;IA4Df,KAAK,IAAI,IAAI;CAGrB;AAGD,eAAO,MAAM,qBAAqB,gBAAuB,CAAC;AA6B1D,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAQ,cAAqC,KAC5C,IAmCF,CAAC"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerMetering = exports.defaultMeteringEngine = exports.MeteringEngine = exports.DEFAULT_MAX_TENANTS = exports.TIER_QUOTAS = void 0;
4
4
  const constants_1 = require("../config/constants");
5
+ const problem_1 = require("../lib/problem");
5
6
  exports.TIER_QUOTAS = {
6
7
  community: {
7
8
  tier: "community",
@@ -144,10 +145,7 @@ const registerMetering = (app, engine = new MeteringEngine()) => {
144
145
  const code = result.statusCode;
145
146
  if (code === 429)
146
147
  reply.header("Retry-After", result.resetSeconds);
147
- return reply.code(code).send({
148
- statusCode: code,
149
- error: code === 413 ? "Payload Too Large" : "Too Many Requests",
150
- message: result.error,
148
+ return (0, problem_1.sendProblem)(reply, code, code === 413 ? "payload-too-large" : "rate-limited", result.error, {
151
149
  tier: result.tier,
152
150
  limit: result.limit,
153
151
  resetSeconds: result.resetSeconds,
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ #!/usr/bin/env node
1
2
  export {};
2
3
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  "use strict";
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -1,6 +1,7 @@
1
1
  import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
2
- export declare const SCOPES: readonly ["crypto:encrypt", "crypto:decrypt", "crypto:sign", "crypto:verify", "crypto:hash", "crypto:kdf", "crypto:keys", "crypto:admin"];
2
+ export declare const SCOPES: readonly ["crypto:encrypt", "crypto:decrypt", "crypto:sign", "crypto:verify", "crypto:hash", "crypto:kdf", "crypto:keys", "crypto:keys:export", "crypto:admin"];
3
3
  export type Scope = (typeof SCOPES)[number];
4
+ export declare const EXPLICIT_SCOPES: readonly Scope[];
4
5
  export interface AuthPayload {
5
6
  sub: string;
6
7
  scopes: Scope[];
@@ -8,7 +9,9 @@ export interface AuthPayload {
8
9
  exp?: number;
9
10
  }
10
11
  export declare function registerAuth(app: FastifyInstance): Promise<void>;
12
+ export declare function exceedsLifetime(payload: AuthPayload, maxAgeSeconds: number, nowSeconds?: number): boolean;
11
13
  export declare function authenticate(request: FastifyRequest, reply: FastifyReply): Promise<AuthPayload | null>;
12
14
  export declare function hasScope(payload: AuthPayload, required: Scope): boolean;
13
15
  export declare function requireScope(payload: AuthPayload, scope: Scope, reply: FastifyReply): boolean;
16
+ export declare function authorizeRoute(request: FastifyRequest, reply: FastifyReply, payload: AuthPayload): boolean;
14
17
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO7E,eAAO,MAAM,MAAM,2IAST,CAAC;AAGX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAG5C,MAAM,WAAW,WAAW;IAE1B,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAEhB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtE;AAUD,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqD7B;AAKD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,GAAG,OAAO,CAIvE;AAKD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,YAAY,GAClB,OAAO,CAST"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAc7E,eAAO,MAAM,MAAM,iKAUT,CAAC;AAGX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAO5C,eAAO,MAAM,eAAe,EAAE,SAAS,KAAK,EAA2B,CAAC;AAGxE,MAAM,WAAW,WAAW;IAE1B,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAEhB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAeD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BtE;AAOD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,MAAsC,GACjD,OAAO,CAIT;AA0DD,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA0B7B;AAKD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,GAAG,OAAO,CAOvE;AAKD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,YAAY,GAClB,OAAO,CAMT;AASD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,GACnB,OAAO,CAeT"}