@shipfox/api-auth 9.2.0 → 10.0.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.
Files changed (82) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +56 -0
  3. package/README.md +32 -8
  4. package/dist/config.d.ts +1 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +4 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/core/administration.d.ts +43 -0
  9. package/dist/core/administration.d.ts.map +1 -0
  10. package/dist/core/administration.js +152 -0
  11. package/dist/core/administration.js.map +1 -0
  12. package/dist/core/auth.d.ts.map +1 -1
  13. package/dist/core/auth.js +2 -5
  14. package/dist/core/auth.js.map +1 -1
  15. package/dist/core/entities/administrator-read-model.d.ts +21 -0
  16. package/dist/core/entities/administrator-read-model.d.ts.map +1 -0
  17. package/dist/core/entities/administrator-read-model.js +3 -0
  18. package/dist/core/entities/administrator-read-model.js.map +1 -0
  19. package/dist/core/errors.d.ts +15 -0
  20. package/dist/core/errors.d.ts.map +1 -1
  21. package/dist/core/errors.js +30 -0
  22. package/dist/core/errors.js.map +1 -1
  23. package/dist/db/admin-grants.d.ts +34 -1
  24. package/dist/db/admin-grants.d.ts.map +1 -1
  25. package/dist/db/admin-grants.js +177 -5
  26. package/dist/db/admin-grants.js.map +1 -1
  27. package/dist/db/admin-users.d.ts +21 -0
  28. package/dist/db/admin-users.d.ts.map +1 -0
  29. package/dist/db/admin-users.js +32 -0
  30. package/dist/db/admin-users.js.map +1 -0
  31. package/dist/db/db.d.ts +256 -0
  32. package/dist/db/db.d.ts.map +1 -1
  33. package/dist/db/db.js +2 -0
  34. package/dist/db/db.js.map +1 -1
  35. package/dist/db/schema/admin-command-results.d.ts +142 -0
  36. package/dist/db/schema/admin-command-results.d.ts.map +1 -0
  37. package/dist/db/schema/admin-command-results.js +21 -0
  38. package/dist/db/schema/admin-command-results.js.map +1 -0
  39. package/dist/index.d.ts +2 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +12 -3
  42. package/dist/index.js.map +1 -1
  43. package/dist/metrics/instance.d.ts +1 -1
  44. package/dist/metrics/instance.d.ts.map +1 -1
  45. package/dist/metrics/instance.js.map +1 -1
  46. package/dist/presentation/routes/administration.d.ts +4 -0
  47. package/dist/presentation/routes/administration.d.ts.map +1 -0
  48. package/dist/presentation/routes/administration.js +267 -0
  49. package/dist/presentation/routes/administration.js.map +1 -0
  50. package/dist/presentation/routes/rate-limit.d.ts +1 -0
  51. package/dist/presentation/routes/rate-limit.d.ts.map +1 -1
  52. package/dist/presentation/routes/rate-limit.js +26 -1
  53. package/dist/presentation/routes/rate-limit.js.map +1 -1
  54. package/dist/tsconfig.test.tsbuildinfo +1 -1
  55. package/drizzle/0002_burly_whizzer.sql +12 -0
  56. package/drizzle/meta/0002_snapshot.json +791 -0
  57. package/drizzle/meta/_journal.json +7 -0
  58. package/package.json +10 -9
  59. package/src/config.ts +4 -0
  60. package/src/core/administration.ts +213 -0
  61. package/src/core/auth-default-signup-policy.test.ts +65 -0
  62. package/src/core/auth.test.ts +5 -0
  63. package/src/core/auth.ts +2 -3
  64. package/src/core/entities/administrator-read-model.ts +23 -0
  65. package/src/core/errors.ts +35 -0
  66. package/src/db/admin-grants.test.ts +1 -7
  67. package/src/db/admin-grants.ts +310 -5
  68. package/src/db/admin-users.ts +58 -0
  69. package/src/db/db.ts +2 -0
  70. package/src/db/schema/admin-command-results.ts +41 -0
  71. package/src/index.test.ts +6 -2
  72. package/src/index.ts +23 -2
  73. package/src/metrics/instance.ts +1 -1
  74. package/src/presentation/auth/refresh-cookie.test.ts +4 -0
  75. package/src/presentation/e2eRoutes/index.test.ts +1 -0
  76. package/src/presentation/routes/administration.test.ts +537 -0
  77. package/src/presentation/routes/administration.ts +276 -0
  78. package/src/presentation/routes/index.test.ts +1 -0
  79. package/src/presentation/routes/rate-limit.ts +26 -2
  80. package/test/globalSetup.ts +6 -2
  81. package/test/routes.ts +10 -1
  82. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 59 files with swc (416.7ms)
2
+ Successfully compiled: 64 files with swc (349.3ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # @shipfox/api-auth
2
2
 
3
+ ## 10.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 6054364: Add bounded administrator user lookup and safe administrator-grant summaries while removing the unbounded grant reader.
8
+
9
+ ### Minor Changes
10
+
11
+ - dd43d63: Moves Auth administration routes to the unversioned `/admin/...` namespace.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [6054364]
16
+ - Updated dependencies [74f9e31]
17
+ - Updated dependencies [e9280fc]
18
+ - @shipfox/api-auth-dto@10.0.0
19
+ - @shipfox/node-fastify@0.4.0
20
+ - @shipfox/api-workspaces-dto@10.0.0
21
+ - @shipfox/api-auth-context@10.0.0
22
+ - @shipfox/node-module@1.0.4
23
+ - @shipfox/api-common-dto@9.2.0
24
+ - @shipfox/api-email-challenges@1.1.6
25
+ - @shipfox/config@1.2.4
26
+ - @shipfox/inter-module@0.2.2
27
+ - @shipfox/node-auth-root-key@0.2.3
28
+ - @shipfox/node-drizzle@0.3.4
29
+ - @shipfox/node-email@0.3.4
30
+ - @shipfox/node-jwt@0.3.2
31
+ - @shipfox/node-mailer@0.2.4
32
+ - @shipfox/node-opentelemetry@0.6.3
33
+ - @shipfox/node-outbox@0.2.6
34
+ - @shipfox/node-postgres@0.4.4
35
+ - @shipfox/node-rate-limit@0.3.2
36
+ - @shipfox/node-tokens@0.3.2
37
+
38
+ ## 9.3.0
39
+
40
+ ### Minor Changes
41
+
42
+ - 10cf63c: Add first-owner bootstrap and administrator grant management routes.
43
+
44
+ ### Patch Changes
45
+
46
+ - c0046d3: Default low-level account creation to the environment-backed signup policy when no explicit policy is supplied.
47
+ - Updated dependencies [10cf63c]
48
+ - Updated dependencies [4425c6d]
49
+ - Updated dependencies [7b6a409]
50
+ - @shipfox/api-auth-dto@9.3.0
51
+ - @shipfox/node-opentelemetry@0.6.3
52
+ - @shipfox/api-workspaces-dto@9.3.0
53
+ - @shipfox/api-auth-context@9.3.0
54
+ - @shipfox/api-email-challenges@1.1.5
55
+ - @shipfox/node-fastify@0.3.4
56
+ - @shipfox/node-mailer@0.2.4
57
+ - @shipfox/node-module@1.0.3
58
+
3
59
  ## 9.2.0
4
60
 
5
61
  ### Minor Changes
package/README.md CHANGED
@@ -68,6 +68,7 @@ Required environment:
68
68
  | `AUTH_SIGNUP_ALLOWED_EMAILS` | none | Comma-separated exact email addresses allowed to create accounts. |
69
69
  | `AUTH_SIGNUP_NOT_ALLOWED_MESSAGE` | none | Description returned when the signup gate blocks an account. Defaults to "This Shipfox deployment does not accept new accounts right now." |
70
70
  | `CLIENT_BASE_URL` | `http://localhost:5173` | Base URL used in email verification and password reset links. |
71
+ | `ADMIN_BOOTSTRAP_TOKEN` | none | Deployment secret accepted once to create the first administrator owner. Set it before bootstrap and remove or rotate it after successful bootstrap. |
71
72
 
72
73
  Email delivery uses the shared `@shipfox/node-mailer` configuration.
73
74
 
@@ -231,6 +232,19 @@ When password login is disabled, the password and email-verification rows in thi
231
232
  > [!IMPORTANT]
232
233
  > Refresh cookies are set with `secure: true`, `httpOnly: true`, and `sameSite: "lax"`. Local browser tests need HTTPS or a test path that handles secure cookies.
233
234
 
235
+ ### Administrator grants
236
+
237
+ All routes are mounted under `/admin/auth/admin-grants` and require an authenticated bearer token. Administrator role checks are enforced in the core layer, not by route-level middleware.
238
+
239
+ | Method | Path | Required role | Result |
240
+ | --- | --- | --- | --- |
241
+ | `POST` | `/bootstrap` | none (deployment token) | Claims the `admin-owner` role for the calling user using `ADMIN_BOOTSTRAP_TOKEN`. Fails with `409 bootstrap-closed` once an active owner exists. |
242
+ | `GET` | `/` | `admin-observer` | Lists bounded local administrator grant summaries with embedded safe user identities. |
243
+ | `POST` | `/` | `admin-owner` | Grants a role to an active user. |
244
+ | `DELETE` | `/:grantId` | `admin-owner` | Revokes a grant. Fails with `409 last-owner` when it would remove the final active owner. |
245
+
246
+ `POST` and `DELETE` routes require an `Idempotency-Key` header; a repeated key replays the same result, and reusing a key with a different command returns `409 idempotency-key-reused`. Every mutation writes a redacted `administration.action.performed` outbox event.
247
+
234
248
  ### Rate limiting
235
249
 
236
250
  The public auth endpoints include an application-layer abuse baseline for open source installs:
@@ -240,6 +254,8 @@ The public auth endpoints include an application-layer abuse baseline for open s
240
254
  | `POST /auth/login` | 60 attempts per 5 minutes | 10 attempts per 15 minutes |
241
255
  | `POST /auth/password-reset` | 30 email-send attempts per hour | 3 email-send attempts per hour |
242
256
  | `POST /auth/verify-email/resend` | Shared with password reset | Shared with password reset |
257
+ | `POST /admin/auth/admin-grants/bootstrap` | 5 attempts per 15 minutes | n/a |
258
+ | `GET /admin/auth/users` | 60 attempts per 5 minutes | n/a |
243
259
 
244
260
  Counters are stored in PostgreSQL as fixed windows in `auth_rate_limits`. IP addresses and email addresses are HMAC-SHA256 values before storage; raw identifiers are not persisted. The identifier key is derived from `AUTH_ROOT_KEY` separately from every token key.
245
261
 
@@ -247,6 +263,12 @@ The limiter uses `request.ip`, so production deployments behind a reverse proxy
247
263
 
248
264
  This app-layer limiter protects semantic auth work such as Argon2 verification and email sending. It is not a volumetric DDoS control. Public production deployments should still use load balancer, CDN, WAF, or firewall rate limits at the network edge.
249
265
 
266
+ ### Administrator user reads
267
+
268
+ `GET /admin/auth/users` requires `admin-observer` and accepts exactly one checked query filter: `id`, `user_id`, or normalized `email`. The response is a bounded `AdministratorUserSummary` containing only the stable user identity, verified-email timestamp, display name, account status, creation timestamp, and current administrator role.
269
+
270
+ `GET /admin/auth/admin-grants` also requires `admin-observer`. It returns at most 100 newest-first `AdministratorGrantSummary` rows per page, with an opaque cursor and a safe embedded user identity. It does not return credentials, sessions, provider payloads, OAuth tokens, refresh tokens, or raw authentication metadata.
271
+
250
272
  ## API
251
273
 
252
274
  The package exports a module factory. Pass it the Workspaces inter-module client from the
@@ -284,20 +306,18 @@ create a normal Shipfox session and set its refresh cookie:
284
306
  import {
285
307
  authCookiePlugin,
286
308
  createSessionForUser,
287
- createEnvironmentSignupPolicy,
288
309
  provisionUser,
289
310
  setRefreshTokenCookie,
290
311
  } from '@shipfox/api-auth';
291
312
  import type {FastifyReply} from 'fastify';
292
313
 
293
314
  export const callbackRoutePlugins = [authCookiePlugin];
294
- const signupPolicy = createEnvironmentSignupPolicy();
295
315
 
296
316
  export async function completeProviderCallback(
297
317
  reply: FastifyReply,
298
318
  profile: {email: string; name?: string},
299
319
  ): Promise<string> {
300
- const user = await provisionUser({...profile, signupPolicy});
320
+ const user = await provisionUser(profile);
301
321
  const session = await createSessionForUser({userId: user.id});
302
322
 
303
323
  setRefreshTokenCookie(reply, session.refreshToken);
@@ -311,11 +331,13 @@ For OAuth providers, require a verified-email claim such as `email_verified`.
311
331
  session for any active, verified account. An unverified provider email could
312
332
  otherwise sign in as an existing password account with the same address.
313
333
 
314
- Pass the same `signupPolicy` to `provisionUser` when signup gating is enabled.
315
- The function checks for an existing user before it calls the policy, so existing
316
- users keep signing in even when their address is no longer allowed. For a new
317
- user, a denied policy throws `SignupNotAllowedError`. Call
318
- `createSessionForUser` only after provisioning succeeds.
334
+ `provisionUser` uses the environment-backed signup policy by default. Pass an
335
+ explicit `signupPolicy` only when the integration owns a replacement policy,
336
+ such as Cloud's database-backed policy. The function checks for an existing
337
+ user before it calls the policy, so existing users keep signing in even when
338
+ their address is no longer allowed. For a new user, a denied policy throws
339
+ `SignupNotAllowedError`. Call `createSessionForUser` only after provisioning
340
+ succeeds.
319
341
 
320
342
  Add `authCookiePlugin` to the callback route group before calling a cookie
321
343
  helper. `getRefreshTokenCookie`, `setRefreshTokenCookie`, and
@@ -389,6 +411,8 @@ The module creates tables with the `auth_` prefix:
389
411
  - `auth_refresh_tokens`
390
412
  - `auth_password_resets`
391
413
  - `auth_rate_limits`
414
+ - `auth_admin_grants`
415
+ - `auth_admin_command_results`
392
416
 
393
417
  Passwords use Argon2id. Password reset tokens and refresh tokens are opaque tokens stored as hashes. Email verification uses the shared email-challenges module.
394
418
 
package/dist/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export declare const config: Readonly<{
2
+ ADMIN_BOOTSTRAP_TOKEN: string | undefined;
2
3
  AUTH_JWT_EXPIRES_IN: string;
3
4
  AUTH_JOB_LEASE_TOKEN_EXPIRES_IN: string;
4
5
  AUTH_RUNNER_SESSION_TOKEN_EXPIRES_IN: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;;;;;;;;kDAiDjB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;kDAqDjB,CAAC"}
package/dist/config.js CHANGED
@@ -1,5 +1,9 @@
1
1
  import { bool, createConfig, num, str } from '@shipfox/config';
2
2
  export const config = createConfig({
3
+ ADMIN_BOOTSTRAP_TOKEN: str({
4
+ desc: 'Deployment secret accepted once to create the first administrator owner. Set it before bootstrap and remove or rotate it after successful bootstrap.',
5
+ default: undefined
6
+ }),
3
7
  AUTH_JWT_EXPIRES_IN: str({
4
8
  desc: 'How long an access token stays valid. Accepts a duration string such as 15m, 1h, or 7d.',
5
9
  default: '15m'
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {bool, createConfig, num, str} from '@shipfox/config';\n\nexport const config = createConfig({\n AUTH_JWT_EXPIRES_IN: str({\n desc: 'How long an access token stays valid. Accepts a duration string such as 15m, 1h, or 7d.',\n default: '15m',\n }),\n AUTH_JOB_LEASE_TOKEN_EXPIRES_IN: str({\n desc: 'How long a job lease token stays valid. Set it longer than the longest job (JOB_MAX_DURATION is 60 minutes) plus a safety margin.',\n default: '90m',\n }),\n AUTH_RUNNER_SESSION_TOKEN_EXPIRES_IN: str({\n desc: 'How long a runner session token stays valid. A revoked registration token can leave existing sessions usable until this lifetime ends.',\n default: '1h',\n }),\n AUTH_REFRESH_TOKEN_EXPIRES_IN_DAYS: num({\n desc: 'How many days a refresh token stays valid before the user must sign in again.',\n default: 14,\n }),\n AUTH_REFRESH_ROTATION_GRACE_SECONDS: num({\n desc: 'Window after a refresh token is rotated during which the now-rotated token is still accepted, so concurrent refreshes from parallel tabs do not log the user out. Reuse past this window is treated as a compromise and revokes the session.',\n default: 30,\n }),\n AUTH_REFRESH_COOKIE_NAME: str({\n desc: 'Name of the browser cookie that stores the refresh token.',\n default: 'shipfox_refresh_token',\n }),\n AUTH_PASSWORD_ENABLED: bool({\n desc: 'Whether password login is available. Use true or false. Defaults to true. When false, password and email-verification routes are not registered, and server startup requires another module to contribute a login method.',\n default: true,\n }),\n AUTH_SIGNUP_GATE_ENABLED: bool({\n desc: 'Whether new account creation is restricted to the configured signup email allowlist. Defaults to false, which allows every signup.',\n default: false,\n }),\n AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS: str({\n desc: 'Comma-separated email domains allowed to create accounts, such as shipfox.io,acme.com. Required when AUTH_SIGNUP_GATE_ENABLED is true unless AUTH_SIGNUP_ALLOWED_EMAILS is set.',\n default: '',\n }),\n AUTH_SIGNUP_ALLOWED_EMAILS: str({\n desc: 'Comma-separated exact email addresses allowed to create accounts. Required when AUTH_SIGNUP_GATE_ENABLED is true unless AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS is set.',\n default: '',\n }),\n AUTH_SIGNUP_NOT_ALLOWED_MESSAGE: str({\n desc: 'Description returned when the signup gate blocks an account. Optional. The default is This Shipfox deployment does not accept new accounts right now.',\n default: undefined,\n }),\n CLIENT_BASE_URL: str({\n desc: 'Base URL of the client app. Used to build links in emails such as password resets.',\n default: 'http://localhost:5173',\n }),\n});\n\nif (\n config.AUTH_SIGNUP_GATE_ENABLED &&\n !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS) &&\n !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAILS)\n) {\n throw new Error(\n 'AUTH_SIGNUP_GATE_ENABLED requires AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS or AUTH_SIGNUP_ALLOWED_EMAILS to be set.',\n );\n}\n\nfunction hasSignupAllowlistEntry(value: string): boolean {\n return value.split(',').some((entry) => entry.trim().length > 0);\n}\n"],"names":["bool","createConfig","num","str","config","AUTH_JWT_EXPIRES_IN","desc","default","AUTH_JOB_LEASE_TOKEN_EXPIRES_IN","AUTH_RUNNER_SESSION_TOKEN_EXPIRES_IN","AUTH_REFRESH_TOKEN_EXPIRES_IN_DAYS","AUTH_REFRESH_ROTATION_GRACE_SECONDS","AUTH_REFRESH_COOKIE_NAME","AUTH_PASSWORD_ENABLED","AUTH_SIGNUP_GATE_ENABLED","AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS","AUTH_SIGNUP_ALLOWED_EMAILS","AUTH_SIGNUP_NOT_ALLOWED_MESSAGE","undefined","CLIENT_BASE_URL","hasSignupAllowlistEntry","Error","value","split","some","entry","trim","length"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,YAAY,EAAEC,GAAG,EAAEC,GAAG,QAAO,kBAAkB;AAE7D,OAAO,MAAMC,SAASH,aAAa;IACjCI,qBAAqBF,IAAI;QACvBG,MAAM;QACNC,SAAS;IACX;IACAC,iCAAiCL,IAAI;QACnCG,MAAM;QACNC,SAAS;IACX;IACAE,sCAAsCN,IAAI;QACxCG,MAAM;QACNC,SAAS;IACX;IACAG,oCAAoCR,IAAI;QACtCI,MAAM;QACNC,SAAS;IACX;IACAI,qCAAqCT,IAAI;QACvCI,MAAM;QACNC,SAAS;IACX;IACAK,0BAA0BT,IAAI;QAC5BG,MAAM;QACNC,SAAS;IACX;IACAM,uBAAuBb,KAAK;QAC1BM,MAAM;QACNC,SAAS;IACX;IACAO,0BAA0Bd,KAAK;QAC7BM,MAAM;QACNC,SAAS;IACX;IACAQ,mCAAmCZ,IAAI;QACrCG,MAAM;QACNC,SAAS;IACX;IACAS,4BAA4Bb,IAAI;QAC9BG,MAAM;QACNC,SAAS;IACX;IACAU,iCAAiCd,IAAI;QACnCG,MAAM;QACNC,SAASW;IACX;IACAC,iBAAiBhB,IAAI;QACnBG,MAAM;QACNC,SAAS;IACX;AACF,GAAG;AAEH,IACEH,OAAOU,wBAAwB,IAC/B,CAACM,wBAAwBhB,OAAOW,iCAAiC,KACjE,CAACK,wBAAwBhB,OAAOY,0BAA0B,GAC1D;IACA,MAAM,IAAIK,MACR;AAEJ;AAEA,SAASD,wBAAwBE,KAAa;IAC5C,OAAOA,MAAMC,KAAK,CAAC,KAAKC,IAAI,CAAC,CAACC,QAAUA,MAAMC,IAAI,GAAGC,MAAM,GAAG;AAChE"}
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {bool, createConfig, num, str} from '@shipfox/config';\n\nexport const config = createConfig({\n ADMIN_BOOTSTRAP_TOKEN: str({\n desc: 'Deployment secret accepted once to create the first administrator owner. Set it before bootstrap and remove or rotate it after successful bootstrap.',\n default: undefined,\n }),\n AUTH_JWT_EXPIRES_IN: str({\n desc: 'How long an access token stays valid. Accepts a duration string such as 15m, 1h, or 7d.',\n default: '15m',\n }),\n AUTH_JOB_LEASE_TOKEN_EXPIRES_IN: str({\n desc: 'How long a job lease token stays valid. Set it longer than the longest job (JOB_MAX_DURATION is 60 minutes) plus a safety margin.',\n default: '90m',\n }),\n AUTH_RUNNER_SESSION_TOKEN_EXPIRES_IN: str({\n desc: 'How long a runner session token stays valid. A revoked registration token can leave existing sessions usable until this lifetime ends.',\n default: '1h',\n }),\n AUTH_REFRESH_TOKEN_EXPIRES_IN_DAYS: num({\n desc: 'How many days a refresh token stays valid before the user must sign in again.',\n default: 14,\n }),\n AUTH_REFRESH_ROTATION_GRACE_SECONDS: num({\n desc: 'Window after a refresh token is rotated during which the now-rotated token is still accepted, so concurrent refreshes from parallel tabs do not log the user out. Reuse past this window is treated as a compromise and revokes the session.',\n default: 30,\n }),\n AUTH_REFRESH_COOKIE_NAME: str({\n desc: 'Name of the browser cookie that stores the refresh token.',\n default: 'shipfox_refresh_token',\n }),\n AUTH_PASSWORD_ENABLED: bool({\n desc: 'Whether password login is available. Use true or false. Defaults to true. When false, password and email-verification routes are not registered, and server startup requires another module to contribute a login method.',\n default: true,\n }),\n AUTH_SIGNUP_GATE_ENABLED: bool({\n desc: 'Whether new account creation is restricted to the configured signup email allowlist. Defaults to false, which allows every signup.',\n default: false,\n }),\n AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS: str({\n desc: 'Comma-separated email domains allowed to create accounts, such as shipfox.io,acme.com. Required when AUTH_SIGNUP_GATE_ENABLED is true unless AUTH_SIGNUP_ALLOWED_EMAILS is set.',\n default: '',\n }),\n AUTH_SIGNUP_ALLOWED_EMAILS: str({\n desc: 'Comma-separated exact email addresses allowed to create accounts. Required when AUTH_SIGNUP_GATE_ENABLED is true unless AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS is set.',\n default: '',\n }),\n AUTH_SIGNUP_NOT_ALLOWED_MESSAGE: str({\n desc: 'Description returned when the signup gate blocks an account. Optional. The default is This Shipfox deployment does not accept new accounts right now.',\n default: undefined,\n }),\n CLIENT_BASE_URL: str({\n desc: 'Base URL of the client app. Used to build links in emails such as password resets.',\n default: 'http://localhost:5173',\n }),\n});\n\nif (\n config.AUTH_SIGNUP_GATE_ENABLED &&\n !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS) &&\n !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAILS)\n) {\n throw new Error(\n 'AUTH_SIGNUP_GATE_ENABLED requires AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS or AUTH_SIGNUP_ALLOWED_EMAILS to be set.',\n );\n}\n\nfunction hasSignupAllowlistEntry(value: string): boolean {\n return value.split(',').some((entry) => entry.trim().length > 0);\n}\n"],"names":["bool","createConfig","num","str","config","ADMIN_BOOTSTRAP_TOKEN","desc","default","undefined","AUTH_JWT_EXPIRES_IN","AUTH_JOB_LEASE_TOKEN_EXPIRES_IN","AUTH_RUNNER_SESSION_TOKEN_EXPIRES_IN","AUTH_REFRESH_TOKEN_EXPIRES_IN_DAYS","AUTH_REFRESH_ROTATION_GRACE_SECONDS","AUTH_REFRESH_COOKIE_NAME","AUTH_PASSWORD_ENABLED","AUTH_SIGNUP_GATE_ENABLED","AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS","AUTH_SIGNUP_ALLOWED_EMAILS","AUTH_SIGNUP_NOT_ALLOWED_MESSAGE","CLIENT_BASE_URL","hasSignupAllowlistEntry","Error","value","split","some","entry","trim","length"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,YAAY,EAAEC,GAAG,EAAEC,GAAG,QAAO,kBAAkB;AAE7D,OAAO,MAAMC,SAASH,aAAa;IACjCI,uBAAuBF,IAAI;QACzBG,MAAM;QACNC,SAASC;IACX;IACAC,qBAAqBN,IAAI;QACvBG,MAAM;QACNC,SAAS;IACX;IACAG,iCAAiCP,IAAI;QACnCG,MAAM;QACNC,SAAS;IACX;IACAI,sCAAsCR,IAAI;QACxCG,MAAM;QACNC,SAAS;IACX;IACAK,oCAAoCV,IAAI;QACtCI,MAAM;QACNC,SAAS;IACX;IACAM,qCAAqCX,IAAI;QACvCI,MAAM;QACNC,SAAS;IACX;IACAO,0BAA0BX,IAAI;QAC5BG,MAAM;QACNC,SAAS;IACX;IACAQ,uBAAuBf,KAAK;QAC1BM,MAAM;QACNC,SAAS;IACX;IACAS,0BAA0BhB,KAAK;QAC7BM,MAAM;QACNC,SAAS;IACX;IACAU,mCAAmCd,IAAI;QACrCG,MAAM;QACNC,SAAS;IACX;IACAW,4BAA4Bf,IAAI;QAC9BG,MAAM;QACNC,SAAS;IACX;IACAY,iCAAiChB,IAAI;QACnCG,MAAM;QACNC,SAASC;IACX;IACAY,iBAAiBjB,IAAI;QACnBG,MAAM;QACNC,SAAS;IACX;AACF,GAAG;AAEH,IACEH,OAAOY,wBAAwB,IAC/B,CAACK,wBAAwBjB,OAAOa,iCAAiC,KACjE,CAACI,wBAAwBjB,OAAOc,0BAA0B,GAC1D;IACA,MAAM,IAAII,MACR;AAEJ;AAEA,SAASD,wBAAwBE,KAAa;IAC5C,OAAOA,MAAMC,KAAK,CAAC,KAAKC,IAAI,CAAC,CAACC,QAAUA,MAAMC,IAAI,GAAGC,MAAM,GAAG;AAChE"}
@@ -0,0 +1,43 @@
1
+ import type { AdminRole } from '@shipfox/api-auth-dto';
2
+ import type { TimestampIdCursor } from '@shipfox/node-drizzle';
3
+ import type { AdminGrant } from './entities/admin-grant.js';
4
+ import type { AdministratorGrantSummary, AdministratorUserSummary } from './entities/administrator-read-model.js';
5
+ import { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError } from './errors.js';
6
+ export declare function hashAdministrationValue(value: string): string;
7
+ export declare function administrationCommandFingerprint(command: string, input: unknown): string;
8
+ export interface AdministrationMutationContext {
9
+ actorId: string;
10
+ idempotencyKey: string;
11
+ correlationId: string;
12
+ }
13
+ export declare function bootstrapFirstAdminOwner(params: AdministrationMutationContext & {
14
+ bootstrapToken: string;
15
+ }): Promise<AdminGrant>;
16
+ export declare function findAdministratorUserSummary(params: {
17
+ actorId: string;
18
+ } & ({
19
+ id: string;
20
+ email?: never;
21
+ } | {
22
+ email: string;
23
+ id?: never;
24
+ })): Promise<AdministratorUserSummary | undefined>;
25
+ export declare function listAdministratorGrantSummaries(params: {
26
+ actorId: string;
27
+ limit: number;
28
+ cursor?: TimestampIdCursor;
29
+ }): Promise<{
30
+ grants: AdministratorGrantSummary[];
31
+ nextCursor: TimestampIdCursor | null;
32
+ }>;
33
+ export declare function grantAdministratorRole(params: AdministrationMutationContext & {
34
+ userId: string;
35
+ role: AdminRole;
36
+ reason: string;
37
+ }): Promise<AdminGrant>;
38
+ export declare function revokeAdministratorGrant(params: AdministrationMutationContext & {
39
+ grantId: string;
40
+ reason: string;
41
+ }): Promise<AdminGrant>;
42
+ export { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError, };
43
+ //# sourceMappingURL=administration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"administration.d.ts","sourceRoot":"","sources":["../../src/core/administration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAErD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAU7D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EACV,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,6BAA6B,EAC7B,+BAA+B,EAC/B,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAQrB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAExF;AAkCD,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,6BAA6B,GAAG;IAAC,cAAc,EAAE,MAAM,CAAA;CAAC,GAC/D,OAAO,CAAC,UAAU,CAAC,CAuBrB;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAAG,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,KAAK,CAAA;CAAC,CAAC,GACtF,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAS/C;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,yBAAyB,EAAE,CAAC;IACpC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACtC,CAAC,CAiBD;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,6BAA6B,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACxF,OAAO,CAAC,UAAU,CAAC,CA0BrB;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,6BAA6B,GAAG;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACxE,OAAO,CAAC,UAAU,CAAC,CAwBrB;AAED,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,6BAA6B,EAC7B,+BAA+B,EAC/B,mBAAmB,EACnB,iBAAiB,GAClB,CAAC"}
@@ -0,0 +1,152 @@
1
+ import { createHash, timingSafeEqual } from 'node:crypto';
2
+ import { createAdministrationActionEvent } from '@shipfox/api-common-dto';
3
+ import { config } from '#config.js';
4
+ import { bootstrapFirstAdminOwner as bootstrapFirstAdminOwnerInDb, grantAdminRoleWithAudit, listAdminGrantSummaries, revokeAdminGrantWithAudit } from '#db/admin-grants.js';
5
+ import { findAdministratorUser as findAdministratorUserInDb } from '#db/admin-users.js';
6
+ import { requireAdminRole } from './admin-role.js';
7
+ import { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError } from './errors.js';
8
+ const ADMIN_OWNER_ROLE = 'admin-owner';
9
+ const ADMIN_OBSERVER_ROLE = 'admin-observer';
10
+ const BOOTSTRAP_COMMAND = 'auth.admin_grant.bootstrap';
11
+ const GRANT_COMMAND = 'auth.admin_grant.grant';
12
+ const REVOKE_COMMAND = 'auth.admin_grant.revoke';
13
+ export function hashAdministrationValue(value) {
14
+ return createHash('sha256').update(value).digest('hex');
15
+ }
16
+ export function administrationCommandFingerprint(command, input) {
17
+ return hashAdministrationValue(`${command}:${JSON.stringify(input)}`);
18
+ }
19
+ function bootstrapTokenMatches(candidate, expected) {
20
+ if (!expected) return false;
21
+ const candidateHash = Buffer.from(hashAdministrationValue(candidate), 'hex');
22
+ const expectedHash = Buffer.from(hashAdministrationValue(expected), 'hex');
23
+ return timingSafeEqual(candidateHash, expectedHash);
24
+ }
25
+ function administrationEvent(params) {
26
+ return createAdministrationActionEvent({
27
+ actorId: params.actorId,
28
+ actorRole: params.actorRole,
29
+ requiredRole: ADMIN_OWNER_ROLE,
30
+ command: params.command,
31
+ targetType: params.targetType,
32
+ targetId: params.targetId,
33
+ reason: params.reason,
34
+ result: 'succeeded',
35
+ correlationId: params.correlationId,
36
+ idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,
37
+ occurredAt: new Date().toISOString()
38
+ });
39
+ }
40
+ export async function bootstrapFirstAdminOwner(params) {
41
+ if (!bootstrapTokenMatches(params.bootstrapToken, config.ADMIN_BOOTSTRAP_TOKEN)) {
42
+ throw new InvalidAdminBootstrapTokenError();
43
+ }
44
+ return await bootstrapFirstAdminOwnerInDb({
45
+ userId: params.actorId,
46
+ actorId: params.actorId,
47
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
48
+ requestFingerprint: administrationCommandFingerprint(BOOTSTRAP_COMMAND, {
49
+ actorId: params.actorId
50
+ }),
51
+ event: administrationEvent({
52
+ actorId: params.actorId,
53
+ actorRole: ADMIN_OWNER_ROLE,
54
+ command: BOOTSTRAP_COMMAND,
55
+ targetType: 'user',
56
+ targetId: params.actorId,
57
+ reason: 'Initial administrator owner bootstrap',
58
+ correlationId: params.correlationId,
59
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
60
+ })
61
+ });
62
+ }
63
+ export async function findAdministratorUserSummary(params) {
64
+ await requireAdminRole({
65
+ userId: params.actorId,
66
+ minimumRole: ADMIN_OBSERVER_ROLE
67
+ });
68
+ const user = await findAdministratorUserInDb('id' in params ? {
69
+ id: params.id
70
+ } : {
71
+ email: params.email
72
+ });
73
+ if (!user) return undefined;
74
+ return user;
75
+ }
76
+ export async function listAdministratorGrantSummaries(params) {
77
+ await requireAdminRole({
78
+ userId: params.actorId,
79
+ minimumRole: ADMIN_OBSERVER_ROLE
80
+ });
81
+ const result = await listAdminGrantSummaries({
82
+ limit: params.limit,
83
+ ...params.cursor ? {
84
+ cursor: params.cursor
85
+ } : {}
86
+ });
87
+ return {
88
+ grants: result.rows.map((row)=>({
89
+ grantId: row.id,
90
+ role: row.role,
91
+ createdAt: row.createdAt,
92
+ revokedAt: row.revokedAt,
93
+ user: row.user
94
+ })),
95
+ nextCursor: result.nextCursor
96
+ };
97
+ }
98
+ export async function grantAdministratorRole(params) {
99
+ const actorRole = await requireAdminRole({
100
+ userId: params.actorId,
101
+ minimumRole: ADMIN_OWNER_ROLE
102
+ });
103
+ return await grantAdminRoleWithAudit({
104
+ userId: params.userId,
105
+ role: params.role,
106
+ actorId: params.actorId,
107
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
108
+ requestFingerprint: administrationCommandFingerprint(GRANT_COMMAND, {
109
+ userId: params.userId,
110
+ role: params.role,
111
+ reason: params.reason
112
+ }),
113
+ event: administrationEvent({
114
+ actorId: params.actorId,
115
+ actorRole,
116
+ command: GRANT_COMMAND,
117
+ targetType: 'user',
118
+ targetId: params.userId,
119
+ reason: params.reason,
120
+ correlationId: params.correlationId,
121
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
122
+ })
123
+ });
124
+ }
125
+ export async function revokeAdministratorGrant(params) {
126
+ const actorRole = await requireAdminRole({
127
+ userId: params.actorId,
128
+ minimumRole: ADMIN_OWNER_ROLE
129
+ });
130
+ return await revokeAdminGrantWithAudit({
131
+ grantId: params.grantId,
132
+ actorId: params.actorId,
133
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
134
+ requestFingerprint: administrationCommandFingerprint(REVOKE_COMMAND, {
135
+ grantId: params.grantId,
136
+ reason: params.reason
137
+ }),
138
+ event: administrationEvent({
139
+ actorId: params.actorId,
140
+ actorRole,
141
+ command: REVOKE_COMMAND,
142
+ targetType: 'admin-grant',
143
+ targetId: params.grantId,
144
+ reason: params.reason,
145
+ correlationId: params.correlationId,
146
+ idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
147
+ })
148
+ });
149
+ }
150
+ export { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError };
151
+
152
+ //# sourceMappingURL=administration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/administration.ts"],"sourcesContent":["import {createHash, timingSafeEqual} from 'node:crypto';\nimport type {AdminRole} from '@shipfox/api-auth-dto';\nimport {createAdministrationActionEvent} from '@shipfox/api-common-dto';\nimport type {TimestampIdCursor} from '@shipfox/node-drizzle';\nimport {config} from '#config.js';\nimport {\n bootstrapFirstAdminOwner as bootstrapFirstAdminOwnerInDb,\n grantAdminRoleWithAudit,\n listAdminGrantSummaries,\n revokeAdminGrantWithAudit,\n} from '#db/admin-grants.js';\nimport {findAdministratorUser as findAdministratorUserInDb} from '#db/admin-users.js';\nimport {requireAdminRole} from './admin-role.js';\nimport type {AdminGrant} from './entities/admin-grant.js';\nimport type {\n AdministratorGrantSummary,\n AdministratorUserSummary,\n} from './entities/administrator-read-model.js';\nimport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n InvalidAdminBootstrapTokenError,\n LastAdminOwnerError,\n UserNotFoundError,\n} from './errors.js';\n\nconst ADMIN_OWNER_ROLE: AdminRole = 'admin-owner';\nconst ADMIN_OBSERVER_ROLE: AdminRole = 'admin-observer';\nconst BOOTSTRAP_COMMAND = 'auth.admin_grant.bootstrap';\nconst GRANT_COMMAND = 'auth.admin_grant.grant';\nconst REVOKE_COMMAND = 'auth.admin_grant.revoke';\n\nexport function hashAdministrationValue(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nexport function administrationCommandFingerprint(command: string, input: unknown): string {\n return hashAdministrationValue(`${command}:${JSON.stringify(input)}`);\n}\n\nfunction bootstrapTokenMatches(candidate: string, expected: string | undefined): boolean {\n if (!expected) return false;\n const candidateHash = Buffer.from(hashAdministrationValue(candidate), 'hex');\n const expectedHash = Buffer.from(hashAdministrationValue(expected), 'hex');\n return timingSafeEqual(candidateHash, expectedHash);\n}\n\nfunction administrationEvent(params: {\n actorId: string;\n actorRole: AdminRole;\n command: string;\n targetType: string;\n targetId: string;\n reason: string;\n correlationId: string;\n idempotencyKeyFingerprint: string;\n}) {\n return createAdministrationActionEvent({\n actorId: params.actorId,\n actorRole: params.actorRole,\n requiredRole: ADMIN_OWNER_ROLE,\n command: params.command,\n targetType: params.targetType,\n targetId: params.targetId,\n reason: params.reason,\n result: 'succeeded',\n correlationId: params.correlationId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n occurredAt: new Date().toISOString(),\n });\n}\n\nexport interface AdministrationMutationContext {\n actorId: string;\n idempotencyKey: string;\n correlationId: string;\n}\n\nexport async function bootstrapFirstAdminOwner(\n params: AdministrationMutationContext & {bootstrapToken: string},\n): Promise<AdminGrant> {\n if (!bootstrapTokenMatches(params.bootstrapToken, config.ADMIN_BOOTSTRAP_TOKEN)) {\n throw new InvalidAdminBootstrapTokenError();\n }\n\n return await bootstrapFirstAdminOwnerInDb({\n userId: params.actorId,\n actorId: params.actorId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n requestFingerprint: administrationCommandFingerprint(BOOTSTRAP_COMMAND, {\n actorId: params.actorId,\n }),\n event: administrationEvent({\n actorId: params.actorId,\n actorRole: ADMIN_OWNER_ROLE,\n command: BOOTSTRAP_COMMAND,\n targetType: 'user',\n targetId: params.actorId,\n reason: 'Initial administrator owner bootstrap',\n correlationId: params.correlationId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n }),\n });\n}\n\nexport async function findAdministratorUserSummary(\n params: {actorId: string} & ({id: string; email?: never} | {email: string; id?: never}),\n): Promise<AdministratorUserSummary | undefined> {\n await requireAdminRole({userId: params.actorId, minimumRole: ADMIN_OBSERVER_ROLE});\n\n const user = await findAdministratorUserInDb(\n 'id' in params ? {id: params.id} : {email: params.email},\n );\n if (!user) return undefined;\n\n return user;\n}\n\nexport async function listAdministratorGrantSummaries(params: {\n actorId: string;\n limit: number;\n cursor?: TimestampIdCursor;\n}): Promise<{\n grants: AdministratorGrantSummary[];\n nextCursor: TimestampIdCursor | null;\n}> {\n await requireAdminRole({userId: params.actorId, minimumRole: ADMIN_OBSERVER_ROLE});\n\n const result = await listAdminGrantSummaries({\n limit: params.limit,\n ...(params.cursor ? {cursor: params.cursor} : {}),\n });\n return {\n grants: result.rows.map((row) => ({\n grantId: row.id,\n role: row.role,\n createdAt: row.createdAt,\n revokedAt: row.revokedAt,\n user: row.user,\n })),\n nextCursor: result.nextCursor,\n };\n}\n\nexport async function grantAdministratorRole(\n params: AdministrationMutationContext & {userId: string; role: AdminRole; reason: string},\n): Promise<AdminGrant> {\n const actorRole = await requireAdminRole({\n userId: params.actorId,\n minimumRole: ADMIN_OWNER_ROLE,\n });\n return await grantAdminRoleWithAudit({\n userId: params.userId,\n role: params.role,\n actorId: params.actorId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n requestFingerprint: administrationCommandFingerprint(GRANT_COMMAND, {\n userId: params.userId,\n role: params.role,\n reason: params.reason,\n }),\n event: administrationEvent({\n actorId: params.actorId,\n actorRole,\n command: GRANT_COMMAND,\n targetType: 'user',\n targetId: params.userId,\n reason: params.reason,\n correlationId: params.correlationId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n }),\n });\n}\n\nexport async function revokeAdministratorGrant(\n params: AdministrationMutationContext & {grantId: string; reason: string},\n): Promise<AdminGrant> {\n const actorRole = await requireAdminRole({\n userId: params.actorId,\n minimumRole: ADMIN_OWNER_ROLE,\n });\n return await revokeAdminGrantWithAudit({\n grantId: params.grantId,\n actorId: params.actorId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n requestFingerprint: administrationCommandFingerprint(REVOKE_COMMAND, {\n grantId: params.grantId,\n reason: params.reason,\n }),\n event: administrationEvent({\n actorId: params.actorId,\n actorRole,\n command: REVOKE_COMMAND,\n targetType: 'admin-grant',\n targetId: params.grantId,\n reason: params.reason,\n correlationId: params.correlationId,\n idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),\n }),\n });\n}\n\nexport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n InvalidAdminBootstrapTokenError,\n LastAdminOwnerError,\n UserNotFoundError,\n};\n"],"names":["createHash","timingSafeEqual","createAdministrationActionEvent","config","bootstrapFirstAdminOwner","bootstrapFirstAdminOwnerInDb","grantAdminRoleWithAudit","listAdminGrantSummaries","revokeAdminGrantWithAudit","findAdministratorUser","findAdministratorUserInDb","requireAdminRole","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","InvalidAdminBootstrapTokenError","LastAdminOwnerError","UserNotFoundError","ADMIN_OWNER_ROLE","ADMIN_OBSERVER_ROLE","BOOTSTRAP_COMMAND","GRANT_COMMAND","REVOKE_COMMAND","hashAdministrationValue","value","update","digest","administrationCommandFingerprint","command","input","JSON","stringify","bootstrapTokenMatches","candidate","expected","candidateHash","Buffer","from","expectedHash","administrationEvent","params","actorId","actorRole","requiredRole","targetType","targetId","reason","result","correlationId","idempotencyKeyFingerprint","occurredAt","Date","toISOString","bootstrapToken","ADMIN_BOOTSTRAP_TOKEN","userId","idempotencyKey","requestFingerprint","event","findAdministratorUserSummary","minimumRole","user","id","email","undefined","listAdministratorGrantSummaries","limit","cursor","grants","rows","map","row","grantId","role","createdAt","revokedAt","nextCursor","grantAdministratorRole","revokeAdministratorGrant"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,SAAS,EAAc,MAAM,uBAAuB,CAAC;AAOlE,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,0CAA0C,CAAC;AAyBlD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EACL,8BAA8B,EAC9B,qBAAqB,EAErB,uBAAuB,EAMvB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAmI7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9E;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG;IAChC,cAAc,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,qBAAqB,EAAE,IAAI,CAAA;KAAC,CAAC;CAC3D,CAAC;AAEF,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CA8C9F;AAED,MAAM,WAAW,0BAA2B,SAAQ,YAAY;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,0BAA2B,SAAQ,WAAW;IAC7D,UAAU,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAC;IACrE,WAAW,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAC/C;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,0BAA0B,CAAC,CAiErC;AAED,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAwBrE;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,yBAAyB,GACjC,8BAA8B,GAC9B,qBAAqB,GACrB,uBAAuB,GACvB,iBAAiB,CAAC;AAEtB,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,0BAA0B,CAAC,CAoBrC;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,2BAA2B,CAAC;CACzC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAoDpC;AAED,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,6BAA6B;IAC5C,qBAAqB,EAAE,IAAI,CAAC;CAC7B;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,2BAA2B,CAAC;CACzC,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAqB1C;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAYzC;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjF;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,2BAA2B,CAAC;CACzC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAsBtC;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB;AAED,wBAAsB,MAAM,CAAC,MAAM,EAAE;IAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAO5F"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"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"}
package/dist/core/auth.js CHANGED
@@ -13,14 +13,11 @@ import { getCurrentAdminRole } from './admin-role.js';
13
13
  import { AuthDependencyUnavailableError, EmailNotVerifiedError, EmailTakenError, InvalidCredentialsError, InvitationEmailMismatchError, SignupNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, TokenInvalidError, UserNotFoundError } from './errors.js';
14
14
  import { signUserToken } from './jwt.js';
15
15
  import { hashPassword, verifyPassword } from './password.js';
16
+ import { createEnvironmentSignupPolicy } from './signup-policy.js';
16
17
  const RESET_TTL_HOURS = 1;
17
18
  const PASSWORD_VERIFICATION_PURPOSE = 'password-verification';
18
19
  const DEFAULT_SIGNUP_NOT_ALLOWED_MESSAGE = 'This Shipfox deployment does not accept new accounts right now.';
19
- const defaultSignupPolicy = {
20
- isSignupAllowed: async ()=>({
21
- allowed: true
22
- })
23
- };
20
+ const defaultSignupPolicy = createEnvironmentSignupPolicy();
24
21
  async function assertSignupAllowed(params) {
25
22
  const result = await (params.signupPolicy ?? defaultSignupPolicy).isSignupAllowed({
26
23
  email: params.email,