@sebastienrousseau/crypto-server 0.0.8 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -56
- package/dist/@types/types.d.ts +1 -2
- package/dist/@types/types.d.ts.map +1 -1
- package/dist/config/auth-policy.d.ts +18 -0
- package/dist/config/auth-policy.d.ts.map +1 -1
- package/dist/config/auth-policy.js +126 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +7 -1
- package/dist/enterprise/metering.d.ts.map +1 -1
- package/dist/enterprise/metering.js +2 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/auth.d.ts +4 -1
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +87 -40
- package/dist/lib/kdf-runner.d.ts +18 -0
- package/dist/lib/kdf-runner.d.ts.map +1 -0
- package/dist/lib/kdf-runner.js +27 -0
- package/dist/lib/key-store.d.ts +37 -0
- package/dist/lib/key-store.d.ts.map +1 -0
- package/dist/lib/key-store.js +223 -0
- package/dist/lib/opaque-store.d.ts +34 -0
- package/dist/lib/opaque-store.d.ts.map +1 -0
- package/dist/lib/opaque-store.js +72 -0
- package/dist/lib/problem.d.ts +67 -0
- package/dist/lib/problem.d.ts.map +1 -0
- package/dist/lib/problem.js +162 -0
- package/dist/routes/v1/decrypt.d.ts.map +1 -1
- package/dist/routes/v1/decrypt.js +24 -16
- package/dist/routes/v1/encrypt.d.ts.map +1 -1
- package/dist/routes/v1/encrypt.js +12 -13
- package/dist/routes/v1/generate.d.ts.map +1 -1
- package/dist/routes/v1/generate.js +22 -25
- package/dist/routes/v1/revoke.d.ts.map +1 -1
- package/dist/routes/v1/revoke.js +6 -11
- package/dist/routes/v1/verify.d.ts.map +1 -1
- package/dist/routes/v1/verify.js +10 -12
- package/dist/routes/v2/algorithms.js +1 -1
- package/dist/routes/v2/compliance.js +1 -1
- package/dist/routes/v2/encrypt.d.ts.map +1 -1
- package/dist/routes/v2/encrypt.js +1 -1
- package/dist/routes/v2/hash.d.ts.map +1 -1
- package/dist/routes/v2/hash.js +1 -1
- package/dist/routes/v2/hpke.d.ts +3 -0
- package/dist/routes/v2/hpke.d.ts.map +1 -0
- package/dist/routes/v2/hpke.js +168 -0
- package/dist/routes/v2/index.d.ts.map +1 -1
- package/dist/routes/v2/index.js +6 -0
- package/dist/routes/v2/kdf.d.ts +5 -0
- package/dist/routes/v2/kdf.d.ts.map +1 -1
- package/dist/routes/v2/kdf.js +27 -12
- package/dist/routes/v2/key-wrap.d.ts.map +1 -1
- package/dist/routes/v2/key-wrap.js +9 -3
- package/dist/routes/v2/keys.d.ts.map +1 -1
- package/dist/routes/v2/keys.js +39 -26
- package/dist/routes/v2/kms.d.ts +7 -0
- package/dist/routes/v2/kms.d.ts.map +1 -0
- package/dist/routes/v2/kms.js +310 -0
- package/dist/routes/v2/mac.d.ts.map +1 -1
- package/dist/routes/v2/mac.js +10 -3
- package/dist/routes/v2/multi-recipient.d.ts.map +1 -1
- package/dist/routes/v2/multi-recipient.js +12 -11
- package/dist/routes/v2/opaque.d.ts +4 -0
- package/dist/routes/v2/opaque.d.ts.map +1 -0
- package/dist/routes/v2/opaque.js +174 -0
- package/dist/routes/v2/password-encrypt.d.ts.map +1 -1
- package/dist/routes/v2/password-encrypt.js +13 -46
- package/dist/routes/v2/password.d.ts +4 -0
- package/dist/routes/v2/password.d.ts.map +1 -1
- package/dist/routes/v2/password.js +28 -53
- package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-hash-sign.js +33 -24
- package/dist/routes/v2/pq-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-sign.js +31 -24
- package/dist/routes/v2/pq.d.ts.map +1 -1
- package/dist/routes/v2/pq.js +57 -38
- package/dist/routes/v2/sealedbox.d.ts.map +1 -1
- package/dist/routes/v2/sealedbox.js +32 -14
- package/dist/routes/v2/secretbox.d.ts.map +1 -1
- package/dist/routes/v2/secretbox.js +10 -3
- package/dist/routes/v2/signing.d.ts.map +1 -1
- package/dist/routes/v2/signing.js +17 -13
- package/dist/routes/v2/stream-schemas.d.ts +296 -0
- package/dist/routes/v2/stream-schemas.d.ts.map +1 -0
- package/dist/routes/v2/stream-schemas.js +207 -0
- package/dist/routes/v2/stream.d.ts.map +1 -1
- package/dist/routes/v2/stream.js +144 -151
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +19 -5
- package/dist/utils/keys.d.ts +17 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +36 -0
- package/dist/utils/route-helpers.d.ts +1 -5
- package/dist/utils/route-helpers.d.ts.map +1 -1
- package/dist/utils/route-helpers.js +16 -10
- package/dist/utils/trace.d.ts +12 -0
- package/dist/utils/trace.d.ts.map +1 -0
- package/dist/utils/trace.js +62 -0
- package/dist/utils/validation.d.ts +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +17 -9
- package/package.json +22 -18
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` |
|
|
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
|
|
177
|
-
| `POST` | `/v2/keys/
|
|
178
|
-
| `POST` | `/v2/keys/
|
|
179
|
-
| `POST` | `/v2/
|
|
180
|
-
| `POST` | `/v2/secretbox/
|
|
181
|
-
| `POST` | `/v2/
|
|
182
|
-
| `POST` | `/v2/sealedbox/
|
|
183
|
-
| `POST` | `/v2/sealedbox/
|
|
184
|
-
| `POST` | `/v2/sealedbox/
|
|
185
|
-
| `POST` | `/v2/
|
|
186
|
-
| `POST` | `/v2/
|
|
187
|
-
| `POST` | `/v2/pq/
|
|
188
|
-
| `POST` | `/v2/pq/
|
|
189
|
-
| `POST` | `/v2/pq/
|
|
190
|
-
| `POST` | `/v2/pq/hybrid/
|
|
191
|
-
| `POST` | `/v2/pq/hybrid/
|
|
192
|
-
| `POST` | `/v2/pq/
|
|
193
|
-
| `POST` | `/v2/pq/dsa/
|
|
194
|
-
| `POST` | `/v2/pq/dsa/
|
|
195
|
-
| `POST` | `/v2/pq/
|
|
196
|
-
| `POST` | `/v2/pq/slh-dsa/
|
|
197
|
-
| `POST` | `/v2/pq/slh-dsa/
|
|
198
|
-
| `
|
|
199
|
-
| `GET` | `/
|
|
200
|
-
| `GET` | `/
|
|
201
|
-
| `GET` | `/
|
|
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,
|
|
215
|
-
|
|
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
|
-
| `
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
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
|
|
package/dist/@types/types.d.ts
CHANGED
|
@@ -20,13 +20,12 @@ export interface IBodyEncrypt {
|
|
|
20
20
|
passphrase: string;
|
|
21
21
|
message: string;
|
|
22
22
|
publicKey: string;
|
|
23
|
-
|
|
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,
|
|
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":"
|
|
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,CAiFxD,CAAC;AAOH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIlD;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,99 @@ 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/stream/pq-encrypt": "crypto:encrypt",
|
|
70
|
+
"POST /v2/stream/multi-pq-encrypt": "crypto:encrypt",
|
|
71
|
+
"POST /v2/decrypt": "crypto:decrypt",
|
|
72
|
+
"POST /v2/secretbox/open": "crypto:decrypt",
|
|
73
|
+
"POST /v2/sealedbox/open": "crypto:decrypt",
|
|
74
|
+
"POST /v2/sealedbox/open-pq": "crypto:decrypt",
|
|
75
|
+
"POST /v2/password/decrypt": "crypto:decrypt",
|
|
76
|
+
"POST /v2/pq/decapsulate": "crypto:decrypt",
|
|
77
|
+
"POST /v2/pq/hybrid/decapsulate": "crypto:decrypt",
|
|
78
|
+
"POST /v2/stream/pq-decrypt": "crypto:decrypt",
|
|
79
|
+
"POST /v2/stream/multi-pq-decrypt": "crypto:decrypt",
|
|
80
|
+
"POST /v2/sign": "crypto:sign",
|
|
81
|
+
"POST /v2/stream/sign": "crypto:sign",
|
|
82
|
+
"POST /v2/pq/dsa/sign": "crypto:sign",
|
|
83
|
+
"POST /v2/pq/slh-dsa/sign": "crypto:sign",
|
|
84
|
+
"POST /v2/hmac": "crypto:sign",
|
|
85
|
+
"POST /v2/verify": "crypto:verify",
|
|
86
|
+
"POST /v2/stream/verify": "crypto:verify",
|
|
87
|
+
"POST /v2/stream/iso20022": "crypto:verify",
|
|
88
|
+
"POST /v2/pq/dsa/verify": "crypto:verify",
|
|
89
|
+
"POST /v2/pq/slh-dsa/verify": "crypto:verify",
|
|
90
|
+
"POST /v2/hmac/verify": "crypto:verify",
|
|
91
|
+
"POST /v2/hash": "crypto:hash",
|
|
92
|
+
"POST /v2/kdf": "crypto:kdf",
|
|
93
|
+
"POST /v2/password/hash": "crypto:kdf",
|
|
94
|
+
"POST /v2/password/verify": "crypto:kdf",
|
|
95
|
+
"POST /v2/keys/generate": "crypto:keys",
|
|
96
|
+
"POST /v2/keys/export": "crypto:keys:export",
|
|
97
|
+
"POST /v2/keys/wrap": "crypto:keys",
|
|
98
|
+
"POST /v2/keys/unwrap": "crypto:keys",
|
|
99
|
+
"POST /v2/pq/keygen": "crypto:keys",
|
|
100
|
+
"POST /v2/pq/hybrid/keygen": "crypto:keys",
|
|
101
|
+
"POST /v2/pq/dsa/keygen": "crypto:keys",
|
|
102
|
+
"POST /v2/pq/slh-dsa/keygen": "crypto:keys",
|
|
103
|
+
"POST /v2/opaque/register/init": exports.AUTHENTICATED,
|
|
104
|
+
"POST /v2/opaque/register/finish": exports.AUTHENTICATED,
|
|
105
|
+
"POST /v2/opaque/login/init": exports.AUTHENTICATED,
|
|
106
|
+
"POST /v2/opaque/login/finish": exports.AUTHENTICATED,
|
|
107
|
+
"POST /v2/hpke/keygen": "crypto:keys",
|
|
108
|
+
"POST /v2/hpke/seal": "crypto:encrypt",
|
|
109
|
+
"POST /v2/hpke/open": "crypto:decrypt",
|
|
110
|
+
"POST /v2/kms/create-key": "crypto:keys",
|
|
111
|
+
"POST /v2/kms/wrap": "crypto:keys",
|
|
112
|
+
"POST /v2/kms/unwrap": "crypto:keys",
|
|
113
|
+
"POST /v2/kms/generate-data-key": "crypto:keys",
|
|
114
|
+
"POST /v2/kms/encrypt": "crypto:encrypt",
|
|
115
|
+
"POST /v2/kms/decrypt": "crypto:decrypt",
|
|
116
|
+
});
|
|
117
|
+
function isPublicRoute(url) {
|
|
118
|
+
return ((0, constants_1.isProbePath)(url) || url.startsWith("/docs") || url.startsWith("/v2/opaque"));
|
|
119
|
+
}
|
|
120
|
+
function routeRequirement(method, url) {
|
|
121
|
+
const verb = method === "HEAD" ? "GET" : method;
|
|
122
|
+
return exports.ROUTE_SCOPES[`${verb} ${url}`];
|
|
123
|
+
}
|
|
124
|
+
function unmappedRoutes(routes) {
|
|
125
|
+
const missing = [];
|
|
126
|
+
for (const route of routes) {
|
|
127
|
+
if (isPublicRoute(route.url))
|
|
128
|
+
continue;
|
|
129
|
+
const methods = Array.isArray(route.method) ? route.method : [route.method];
|
|
130
|
+
for (const method of methods) {
|
|
131
|
+
if (routeRequirement(method, route.url) === undefined) {
|
|
132
|
+
missing.push(`${method} ${route.url}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return missing;
|
|
137
|
+
}
|
|
138
|
+
function assertRoutesCovered(routes) {
|
|
139
|
+
const missing = unmappedRoutes(routes);
|
|
140
|
+
if (missing.length > 0) {
|
|
141
|
+
throw new Error(`Routes without an authorization policy: ${missing.join(", ")}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
18
144
|
//# sourceMappingURL=auth-policy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAQ5D,eAAO,MAAM,WAAW,QAA+B,CAAC;AAMxD,eAAO,MAAM,IAAI,QAAqC,CAAC;AAMvD,eAAO,MAAM,IAAI,iBAA8B,CAAC;AAMhD,eAAO,MAAM,QAAQ,QAAoC,CAAC;AAsB1D,eAAO,MAAM,aAAa,UAMzB,CAAC;AAMF,eAAO,MAAM,cAAc,EAAE,oBAa5B,CAAC;AAOF,eAAO,MAAM,eAAe,EAAE,sBAM7B,CAAC;AAOF,eAAO,MAAM,aAAa,EAAE,oBAG3B,CAAC;AAOF,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAQ5D,eAAO,MAAM,WAAW,QAA+B,CAAC;AAMxD,eAAO,MAAM,IAAI,QAAqC,CAAC;AAMvD,eAAO,MAAM,IAAI,iBAA8B,CAAC;AAMhD,eAAO,MAAM,QAAQ,QAAoC,CAAC;AAsB1D,eAAO,MAAM,aAAa,UAMzB,CAAC;AAMF,eAAO,MAAM,cAAc,EAAE,oBAa5B,CAAC;AAOF,eAAO,MAAM,eAAe,EAAE,sBAM7B,CAAC;AAOF,eAAO,MAAM,aAAa,EAAE,oBAG3B,CAAC;AAOF,eAAO,MAAM,WAAW,EAAE,kBAazB,CAAC;AAOF,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,CAK1C,CAAC;AAKH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,OACN,CAAC;AAMrC,eAAO,MAAM,gBAAgB;;;;qBAgBV;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAG,OAAO;;;;;;;;8BAiBnC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE;YAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;SAAE,CAAA;KAAE,WAChD;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;;;;;;;;CAoB3E,CAAC;AAOF,eAAO,MAAM,mBAAmB,QAAO,MAKtC,CAAC;AAMF,eAAO,MAAM,kBAAkB;;;CAK9B,CAAC"}
|
package/dist/config/constants.js
CHANGED
|
@@ -52,7 +52,13 @@ exports.corsOptions = {
|
|
|
52
52
|
? process.env["CORS_ORIGIN"].split(",").map((o) => o.trim())
|
|
53
53
|
: false,
|
|
54
54
|
methods: ["GET", "POST"],
|
|
55
|
-
allowedHeaders: [
|
|
55
|
+
allowedHeaders: [
|
|
56
|
+
"Content-Type",
|
|
57
|
+
"x-api-key",
|
|
58
|
+
"Authorization",
|
|
59
|
+
"x-request-id",
|
|
60
|
+
"traceparent",
|
|
61
|
+
],
|
|
56
62
|
credentials: true,
|
|
57
63
|
};
|
|
58
64
|
exports.PROBE_PATHS = new Set([
|
|
@@ -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;
|
|
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
|
|
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
package/dist/index.js
CHANGED
package/dist/lib/auth.d.ts
CHANGED
|
@@ -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
|
package/dist/lib/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"
|
|
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"}
|