@shipfox/api-auth 9.1.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +41 -0
- package/README.md +44 -2
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +26 -0
- package/dist/config.js.map +1 -1
- package/dist/core/admin-role-model.d.ts +5 -0
- package/dist/core/admin-role-model.d.ts.map +1 -0
- package/dist/core/admin-role-model.js +18 -0
- package/dist/core/admin-role-model.js.map +1 -0
- package/dist/core/admin-role.d.ts +13 -0
- package/dist/core/admin-role.d.ts.map +1 -0
- package/dist/core/admin-role.js +21 -0
- package/dist/core/admin-role.js.map +1 -0
- package/dist/core/administration.d.ts +27 -0
- package/dist/core/administration.d.ts.map +1 -0
- package/dist/core/administration.js +122 -0
- package/dist/core/administration.js.map +1 -0
- package/dist/core/auth.d.ts +9 -0
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +68 -20
- package/dist/core/auth.js.map +1 -1
- package/dist/core/entities/admin-grant.d.ts +10 -0
- package/dist/core/entities/admin-grant.d.ts.map +1 -0
- package/dist/core/entities/admin-grant.js +3 -0
- package/dist/core/entities/admin-grant.js.map +1 -0
- package/dist/core/errors.d.ts +25 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +49 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/ports.d.ts +13 -0
- package/dist/core/ports.d.ts.map +1 -0
- package/dist/core/ports.js +3 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/signup-policy.d.ts +10 -0
- package/dist/core/signup-policy.d.ts.map +1 -0
- package/dist/core/signup-policy.js +39 -0
- package/dist/core/signup-policy.js.map +1 -0
- package/dist/db/admin-grants.d.ts +33 -0
- package/dist/db/admin-grants.d.ts.map +1 -0
- package/dist/db/admin-grants.js +193 -0
- package/dist/db/admin-grants.js.map +1 -0
- package/dist/db/db.d.ts +474 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +4 -0
- package/dist/db/db.js.map +1 -1
- package/dist/db/schema/admin-command-results.d.ts +142 -0
- package/dist/db/schema/admin-command-results.d.ts.map +1 -0
- package/dist/db/schema/admin-command-results.js +21 -0
- package/dist/db/schema/admin-command-results.js.map +1 -0
- package/dist/db/schema/admin-grants.d.ts +115 -0
- package/dist/db/schema/admin-grants.d.ts.map +1 -0
- package/dist/db/schema/admin-grants.js +42 -0
- package/dist/db/schema/admin-grants.js.map +1 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -4
- package/dist/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +1 -1
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/dto/user.d.ts +2 -1
- package/dist/presentation/dto/user.d.ts.map +1 -1
- package/dist/presentation/dto/user.js +2 -1
- package/dist/presentation/dto/user.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +26 -2
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/administration.d.ts +3 -0
- package/dist/presentation/routes/administration.d.ts.map +1 -0
- package/dist/presentation/routes/administration.js +186 -0
- package/dist/presentation/routes/administration.js.map +1 -0
- package/dist/presentation/routes/index.d.ts +2 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +2 -2
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/rate-limit.d.ts +1 -0
- package/dist/presentation/routes/rate-limit.d.ts.map +1 -1
- package/dist/presentation/routes/rate-limit.js +20 -1
- package/dist/presentation/routes/rate-limit.js.map +1 -1
- package/dist/presentation/routes/registration/signup.d.ts +2 -1
- package/dist/presentation/routes/registration/signup.d.ts.map +1 -1
- package/dist/presentation/routes/registration/signup.js +14 -3
- package/dist/presentation/routes/registration/signup.js.map +1 -1
- package/dist/presentation/routes/session/me.d.ts.map +1 -1
- package/dist/presentation/routes/session/me.js +5 -1
- package/dist/presentation/routes/session/me.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0001_brainy_shriek.sql +14 -0
- package/drizzle/0002_burly_whizzer.sql +12 -0
- package/drizzle/meta/0001_snapshot.json +702 -0
- package/drizzle/meta/0002_snapshot.json +791 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +10 -9
- package/src/config.test.ts +39 -0
- package/src/config.ts +34 -0
- package/src/core/admin-role-model.ts +25 -0
- package/src/core/admin-role.test.ts +39 -0
- package/src/core/admin-role.ts +25 -0
- package/src/core/administration.ts +172 -0
- package/src/core/auth-default-signup-policy.test.ts +65 -0
- package/src/core/auth.test.ts +115 -0
- package/src/core/auth.ts +77 -21
- package/src/core/entities/admin-grant.ts +10 -0
- package/src/core/errors.ts +59 -0
- package/src/core/jwt.test.ts +1 -0
- package/src/core/ports.ts +7 -0
- package/src/core/signup-policy.test.ts +78 -0
- package/src/core/signup-policy.ts +42 -0
- package/src/db/admin-grants.test.ts +57 -0
- package/src/db/admin-grants.ts +340 -0
- package/src/db/db.ts +4 -0
- package/src/db/schema/admin-command-results.ts +41 -0
- package/src/db/schema/admin-grants.ts +49 -0
- package/src/index.test.ts +58 -1
- package/src/index.ts +47 -6
- package/src/metrics/instance.ts +1 -1
- package/src/presentation/auth/refresh-cookie.test.ts +4 -0
- package/src/presentation/dto/user.ts +7 -2
- package/src/presentation/e2eRoutes/index.test.ts +1 -0
- package/src/presentation/inter-module.test.ts +47 -0
- package/src/presentation/inter-module.ts +22 -1
- package/src/presentation/routes/administration.test.ts +253 -0
- package/src/presentation/routes/administration.ts +195 -0
- package/src/presentation/routes/index.test.ts +1 -0
- package/src/presentation/routes/index.ts +3 -1
- package/src/presentation/routes/rate-limit.ts +23 -2
- package/src/presentation/routes/registration/signup.test.ts +26 -0
- package/src/presentation/routes/registration/signup.ts +22 -2
- package/src/presentation/routes/session/login.test.ts +1 -0
- package/src/presentation/routes/session/me.test.ts +18 -2
- package/src/presentation/routes/session/me.ts +5 -1
- package/test/globalSetup.ts +6 -2
- package/test/routes.ts +7 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 62 files with swc (608.87ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @shipfox/api-auth
|
|
2
2
|
|
|
3
|
+
## 9.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 10cf63c: Add first-owner bootstrap and administrator grant management routes.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- c0046d3: Default low-level account creation to the environment-backed signup policy when no explicit policy is supplied.
|
|
12
|
+
- Updated dependencies [10cf63c]
|
|
13
|
+
- Updated dependencies [4425c6d]
|
|
14
|
+
- Updated dependencies [7b6a409]
|
|
15
|
+
- @shipfox/api-auth-dto@9.3.0
|
|
16
|
+
- @shipfox/node-opentelemetry@0.6.3
|
|
17
|
+
- @shipfox/api-workspaces-dto@9.3.0
|
|
18
|
+
- @shipfox/api-auth-context@9.3.0
|
|
19
|
+
- @shipfox/api-email-challenges@1.1.5
|
|
20
|
+
- @shipfox/node-fastify@0.3.4
|
|
21
|
+
- @shipfox/node-mailer@0.2.4
|
|
22
|
+
- @shipfox/node-module@1.0.3
|
|
23
|
+
|
|
24
|
+
## 9.2.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- bd7c46b: Thread an optional signup policy through API Auth module composition in preparation for signup enforcement.
|
|
29
|
+
- 456c884: Add Auth-owned local administrator grants and server-side role evaluation.
|
|
30
|
+
- 36adf25: Guards password and external-identity account creation with the signup policy.
|
|
31
|
+
- f31bee6: Adds the environment-variable signup policy and its Auth-prefixed configuration.
|
|
32
|
+
- 63c0e5b: Adds the signup policy port and denial error to API Auth.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- b321700: Default the Auth module to its environment-backed signup policy when no custom policy is provided.
|
|
37
|
+
- ad36e26: Return a bounded signup-not-allowed message from the password signup route.
|
|
38
|
+
- Updated dependencies [456c884]
|
|
39
|
+
- @shipfox/api-auth-dto@9.2.0
|
|
40
|
+
- @shipfox/api-email-challenges@1.1.4
|
|
41
|
+
- @shipfox/api-workspaces-dto@9.2.0
|
|
42
|
+
- @shipfox/api-auth-context@9.2.0
|
|
43
|
+
|
|
3
44
|
## 9.1.0
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -63,10 +63,22 @@ Required environment:
|
|
|
63
63
|
| `AUTH_REFRESH_ROTATION_GRACE_SECONDS` | `30` | Grace window for accepting a just-rotated refresh token during concurrent refreshes. |
|
|
64
64
|
| `AUTH_REFRESH_COOKIE_NAME` | `shipfox_refresh_token` | HTTP cookie name for refresh sessions. |
|
|
65
65
|
| `AUTH_PASSWORD_ENABLED` | `true` | Enables password and email-verification routes. Set to `false` when another module provides login. Server construction fails if no login method is available. |
|
|
66
|
+
| `AUTH_SIGNUP_GATE_ENABLED` | `false` | Restricts new account creation to the configured signup email allowlist. Requires `AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS` or `AUTH_SIGNUP_ALLOWED_EMAILS` to be set. |
|
|
67
|
+
| `AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS` | none | Comma-separated email domains allowed to create accounts, such as `shipfox.io,acme.com`. |
|
|
68
|
+
| `AUTH_SIGNUP_ALLOWED_EMAILS` | none | Comma-separated exact email addresses allowed to create accounts. |
|
|
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." |
|
|
66
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. |
|
|
67
72
|
|
|
68
73
|
Email delivery uses the shared `@shipfox/node-mailer` configuration.
|
|
69
74
|
|
|
75
|
+
The signup gate is off by default. When it is on, provide at least one non-empty
|
|
76
|
+
entry in `AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS` or `AUTH_SIGNUP_ALLOWED_EMAILS`.
|
|
77
|
+
Startup fails when both lists are empty. Values are trimmed and lowercased.
|
|
78
|
+
The policy matches exact email addresses or exact domains. It does not match
|
|
79
|
+
subdomains or wildcards. `createAuthModule` applies these settings by default;
|
|
80
|
+
pass a `signupPolicy` to replace the environment-backed policy.
|
|
81
|
+
|
|
70
82
|
When `AUTH_PASSWORD_ENABLED=false`, the module does not register signup, login, password-reset, password-change, or email-verification routes. Refresh, logout, and current-session routes stay available. Another module must contribute a login method before the API server starts.
|
|
71
83
|
|
|
72
84
|
## Security model
|
|
@@ -202,7 +214,7 @@ All routes are mounted under `/auth`.
|
|
|
202
214
|
|
|
203
215
|
| Method | Path | Auth | Result |
|
|
204
216
|
| --- | --- | --- | --- |
|
|
205
|
-
| `POST` | `/signup` | none | Creates a user and sends an eight-digit email verification code. |
|
|
217
|
+
| `POST` | `/signup` | none | Creates a user and sends an eight-digit email verification code. A denied new signup returns `403` with error code `signup-not-allowed` and the policy message. |
|
|
206
218
|
| `POST` | `/verify-email/confirm` | none | Confirms a verification code, returns an access token, and sets the refresh cookie. |
|
|
207
219
|
| `POST` | `/verify-email/resend` | none | Sends a new verification code when the account is eligible. |
|
|
208
220
|
| `POST` | `/login` | none | Returns an access token and sets the refresh cookie. |
|
|
@@ -220,6 +232,19 @@ When password login is disabled, the password and email-verification rows in thi
|
|
|
220
232
|
> [!IMPORTANT]
|
|
221
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.
|
|
222
234
|
|
|
235
|
+
### Administrator grants
|
|
236
|
+
|
|
237
|
+
All routes are mounted under `/admin/v1/auth/admin-grants` and require an authenticated bearer token. Ownership is 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-owner` | Lists local administrator grants. |
|
|
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
|
+
|
|
223
248
|
### Rate limiting
|
|
224
249
|
|
|
225
250
|
The public auth endpoints include an application-layer abuse baseline for open source installs:
|
|
@@ -229,6 +254,7 @@ The public auth endpoints include an application-layer abuse baseline for open s
|
|
|
229
254
|
| `POST /auth/login` | 60 attempts per 5 minutes | 10 attempts per 15 minutes |
|
|
230
255
|
| `POST /auth/password-reset` | 30 email-send attempts per hour | 3 email-send attempts per hour |
|
|
231
256
|
| `POST /auth/verify-email/resend` | Shared with password reset | Shared with password reset |
|
|
257
|
+
| `POST /admin/v1/auth/admin-grants/bootstrap` | 5 attempts per 15 minutes | n/a |
|
|
232
258
|
|
|
233
259
|
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.
|
|
234
260
|
|
|
@@ -244,7 +270,9 @@ application composition:
|
|
|
244
270
|
```ts
|
|
245
271
|
import {createAuthModule} from '@shipfox/api-auth';
|
|
246
272
|
|
|
247
|
-
const authModule = createAuthModule({
|
|
273
|
+
const authModule = createAuthModule({
|
|
274
|
+
workspaces,
|
|
275
|
+
});
|
|
248
276
|
```
|
|
249
277
|
|
|
250
278
|
It also exports lower-level pieces for tests and advanced integration:
|
|
@@ -256,6 +284,7 @@ It also exports lower-level pieces for tests and advanced integration:
|
|
|
256
284
|
- `createLeaseTokenAuthMethod()`: the Fastify auth method for job lease tokens.
|
|
257
285
|
- `issueRunnerSessionToken(claims)` / `verifyRunnerSessionToken(token)`: mint and verify runner session tokens.
|
|
258
286
|
- `issueJobLeaseToken(claims)` / `verifyJobLeaseToken(token)`: mint and verify job lease tokens.
|
|
287
|
+
- `createEnvironmentSignupPolicy()`: creates the environment-backed signup policy used by default. Pass `signupPolicy` to `createAuthModule` to replace it.
|
|
259
288
|
- `getClientContext(request)`: reads the authenticated user context from a Fastify request.
|
|
260
289
|
- `getAuthenticatedSessionContext(request)`: resolves an authenticated request to its user ID and active refresh-session ID.
|
|
261
290
|
- `findUserByEmail({email})`: read-only lookup of the current owner of a normalized email; see below.
|
|
@@ -295,6 +324,14 @@ For OAuth providers, require a verified-email claim such as `email_verified`.
|
|
|
295
324
|
session for any active, verified account. An unverified provider email could
|
|
296
325
|
otherwise sign in as an existing password account with the same address.
|
|
297
326
|
|
|
327
|
+
`provisionUser` uses the environment-backed signup policy by default. Pass an
|
|
328
|
+
explicit `signupPolicy` only when the integration owns a replacement policy,
|
|
329
|
+
such as Cloud's database-backed policy. The function checks for an existing
|
|
330
|
+
user before it calls the policy, so existing users keep signing in even when
|
|
331
|
+
their address is no longer allowed. For a new user, a denied policy throws
|
|
332
|
+
`SignupNotAllowedError`. Call `createSessionForUser` only after provisioning
|
|
333
|
+
succeeds.
|
|
334
|
+
|
|
298
335
|
Add `authCookiePlugin` to the callback route group before calling a cookie
|
|
299
336
|
helper. `getRefreshTokenCookie`, `setRefreshTokenCookie`, and
|
|
300
337
|
`clearRefreshTokenCookie` use the configured cookie name and the `/auth` path.
|
|
@@ -367,12 +404,17 @@ The module creates tables with the `auth_` prefix:
|
|
|
367
404
|
- `auth_refresh_tokens`
|
|
368
405
|
- `auth_password_resets`
|
|
369
406
|
- `auth_rate_limits`
|
|
407
|
+
- `auth_admin_grants`
|
|
408
|
+
- `auth_admin_command_results`
|
|
370
409
|
|
|
371
410
|
Passwords use Argon2id. Password reset tokens and refresh tokens are opaque tokens stored as hashes. Email verification uses the shared email-challenges module.
|
|
372
411
|
|
|
373
412
|
## Behavior Notes
|
|
374
413
|
|
|
375
414
|
- Signup sends an eight-digit verification code and returns the new user with its challenge ID.
|
|
415
|
+
- Signup gating blocks account creation only. Existing users keep signing in, even when their address is not on the current allowlist.
|
|
416
|
+
- A denied password signup returns `403` with error code `signup-not-allowed`. The policy message is capped at 500 characters.
|
|
417
|
+
- Invitation signup validates the invitation and bypasses the signup policy. Invitations remain a separate authorization path.
|
|
376
418
|
- Login only succeeds for active users with verified email addresses and a password hash.
|
|
377
419
|
- Refresh tokens rotate on each refresh.
|
|
378
420
|
- Password reset tokens and email challenge proofs are consumed once.
|
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;
|
|
@@ -6,6 +7,10 @@ export declare const config: Readonly<{
|
|
|
6
7
|
AUTH_REFRESH_ROTATION_GRACE_SECONDS: number;
|
|
7
8
|
AUTH_REFRESH_COOKIE_NAME: string;
|
|
8
9
|
AUTH_PASSWORD_ENABLED: boolean;
|
|
10
|
+
AUTH_SIGNUP_GATE_ENABLED: boolean;
|
|
11
|
+
AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS: string;
|
|
12
|
+
AUTH_SIGNUP_ALLOWED_EMAILS: string;
|
|
13
|
+
AUTH_SIGNUP_NOT_ALLOWED_MESSAGE: string | undefined;
|
|
9
14
|
CLIENT_BASE_URL: string;
|
|
10
15
|
} & import("@shipfox/config").CleanedEnvAccessors>;
|
|
11
16
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM
|
|
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'
|
|
@@ -28,10 +32,32 @@ export const config = createConfig({
|
|
|
28
32
|
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.',
|
|
29
33
|
default: true
|
|
30
34
|
}),
|
|
35
|
+
AUTH_SIGNUP_GATE_ENABLED: bool({
|
|
36
|
+
desc: 'Whether new account creation is restricted to the configured signup email allowlist. Defaults to false, which allows every signup.',
|
|
37
|
+
default: false
|
|
38
|
+
}),
|
|
39
|
+
AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS: str({
|
|
40
|
+
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.',
|
|
41
|
+
default: ''
|
|
42
|
+
}),
|
|
43
|
+
AUTH_SIGNUP_ALLOWED_EMAILS: str({
|
|
44
|
+
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.',
|
|
45
|
+
default: ''
|
|
46
|
+
}),
|
|
47
|
+
AUTH_SIGNUP_NOT_ALLOWED_MESSAGE: str({
|
|
48
|
+
desc: 'Description returned when the signup gate blocks an account. Optional. The default is This Shipfox deployment does not accept new accounts right now.',
|
|
49
|
+
default: undefined
|
|
50
|
+
}),
|
|
31
51
|
CLIENT_BASE_URL: str({
|
|
32
52
|
desc: 'Base URL of the client app. Used to build links in emails such as password resets.',
|
|
33
53
|
default: 'http://localhost:5173'
|
|
34
54
|
})
|
|
35
55
|
});
|
|
56
|
+
if (config.AUTH_SIGNUP_GATE_ENABLED && !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS) && !hasSignupAllowlistEntry(config.AUTH_SIGNUP_ALLOWED_EMAILS)) {
|
|
57
|
+
throw new Error('AUTH_SIGNUP_GATE_ENABLED requires AUTH_SIGNUP_ALLOWED_EMAIL_DOMAINS or AUTH_SIGNUP_ALLOWED_EMAILS to be set.');
|
|
58
|
+
}
|
|
59
|
+
function hasSignupAllowlistEntry(value) {
|
|
60
|
+
return value.split(',').some((entry)=>entry.trim().length > 0);
|
|
61
|
+
}
|
|
36
62
|
|
|
37
63
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -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 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"],"names":["bool","createConfig","num","str","config","
|
|
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,5 @@
|
|
|
1
|
+
import type { AdminRole } from '@shipfox/api-auth-dto';
|
|
2
|
+
export declare const ADMIN_ROLES: readonly AdminRole[];
|
|
3
|
+
export declare function hasMinimumAdminRole(role: AdminRole, minimumRole: AdminRole): boolean;
|
|
4
|
+
export declare function highestAdminRole(roles: readonly AdminRole[]): AdminRole | null;
|
|
5
|
+
//# sourceMappingURL=admin-role-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-role-model.d.ts","sourceRoot":"","sources":["../../src/core/admin-role-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAI3C,CAAC;AAQF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,GAAG,OAAO,CAEpF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,CAM9E"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const ADMIN_ROLES = [
|
|
2
|
+
'admin-observer',
|
|
3
|
+
'admin-operator',
|
|
4
|
+
'admin-owner'
|
|
5
|
+
];
|
|
6
|
+
const ADMIN_ROLE_RANK = {
|
|
7
|
+
'admin-observer': 1,
|
|
8
|
+
'admin-operator': 2,
|
|
9
|
+
'admin-owner': 3
|
|
10
|
+
};
|
|
11
|
+
export function hasMinimumAdminRole(role, minimumRole) {
|
|
12
|
+
return ADMIN_ROLE_RANK[role] >= ADMIN_ROLE_RANK[minimumRole];
|
|
13
|
+
}
|
|
14
|
+
export function highestAdminRole(roles) {
|
|
15
|
+
return roles.reduce((highest, role)=>highest === null || ADMIN_ROLE_RANK[role] > ADMIN_ROLE_RANK[highest] ? role : highest, null);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=admin-role-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/admin-role-model.ts"],"sourcesContent":["import type {AdminRole} from '@shipfox/api-auth-dto';\n\nexport const ADMIN_ROLES: readonly AdminRole[] = [\n 'admin-observer',\n 'admin-operator',\n 'admin-owner',\n];\n\nconst ADMIN_ROLE_RANK: Record<AdminRole, number> = {\n 'admin-observer': 1,\n 'admin-operator': 2,\n 'admin-owner': 3,\n};\n\nexport function hasMinimumAdminRole(role: AdminRole, minimumRole: AdminRole): boolean {\n return ADMIN_ROLE_RANK[role] >= ADMIN_ROLE_RANK[minimumRole];\n}\n\nexport function highestAdminRole(roles: readonly AdminRole[]): AdminRole | null {\n return roles.reduce<AdminRole | null>(\n (highest, role) =>\n highest === null || ADMIN_ROLE_RANK[role] > ADMIN_ROLE_RANK[highest] ? role : highest,\n null,\n );\n}\n"],"names":["ADMIN_ROLES","ADMIN_ROLE_RANK","hasMinimumAdminRole","role","minimumRole","highestAdminRole","roles","reduce","highest"],"mappings":"AAEA,OAAO,MAAMA,cAAoC;IAC/C;IACA;IACA;CACD,CAAC;AAEF,MAAMC,kBAA6C;IACjD,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;AACjB;AAEA,OAAO,SAASC,oBAAoBC,IAAe,EAAEC,WAAsB;IACzE,OAAOH,eAAe,CAACE,KAAK,IAAIF,eAAe,CAACG,YAAY;AAC9D;AAEA,OAAO,SAASC,iBAAiBC,KAA2B;IAC1D,OAAOA,MAAMC,MAAM,CACjB,CAACC,SAASL,OACRK,YAAY,QAAQP,eAAe,CAACE,KAAK,GAAGF,eAAe,CAACO,QAAQ,GAAGL,OAAOK,SAChF;AAEJ"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AdminRole } from '@shipfox/api-auth-dto';
|
|
2
|
+
export { ADMIN_ROLES, hasMinimumAdminRole, highestAdminRole } from './admin-role-model.js';
|
|
3
|
+
export declare function getCurrentAdminRole(params: {
|
|
4
|
+
userId: string;
|
|
5
|
+
}): Promise<AdminRole | null>;
|
|
6
|
+
export declare function requireAdminRole(params: {
|
|
7
|
+
userId: string;
|
|
8
|
+
minimumRole: AdminRole;
|
|
9
|
+
}): Promise<AdminRole>;
|
|
10
|
+
export declare function revokeAdminGrant(params: {
|
|
11
|
+
grantId: string;
|
|
12
|
+
}): Promise<import("./entities/admin-grant.js").AdminGrant | undefined>;
|
|
13
|
+
//# sourceMappingURL=admin-role.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-role.d.ts","sourceRoot":"","sources":["../../src/core/admin-role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAKrD,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAEzF,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAE7F;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,SAAS,CAAC;CACxB,GAAG,OAAO,CAAC,SAAS,CAAC,CAMrB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,uEAE/D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { findCurrentAdminRole, revokeAdminGrant as revokeAdminGrantInDb } from '#db/admin-grants.js';
|
|
2
|
+
import { hasMinimumAdminRole } from './admin-role-model.js';
|
|
3
|
+
import { AdminRoleRequiredError } from './errors.js';
|
|
4
|
+
export { ADMIN_ROLES, hasMinimumAdminRole, highestAdminRole } from './admin-role-model.js';
|
|
5
|
+
export async function getCurrentAdminRole(params) {
|
|
6
|
+
return await findCurrentAdminRole(params);
|
|
7
|
+
}
|
|
8
|
+
export async function requireAdminRole(params) {
|
|
9
|
+
const role = await getCurrentAdminRole({
|
|
10
|
+
userId: params.userId
|
|
11
|
+
});
|
|
12
|
+
if (!role || !hasMinimumAdminRole(role, params.minimumRole)) {
|
|
13
|
+
throw new AdminRoleRequiredError(params.minimumRole);
|
|
14
|
+
}
|
|
15
|
+
return role;
|
|
16
|
+
}
|
|
17
|
+
export async function revokeAdminGrant(params) {
|
|
18
|
+
return await revokeAdminGrantInDb(params);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=admin-role.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/admin-role.ts"],"sourcesContent":["import type {AdminRole} from '@shipfox/api-auth-dto';\nimport {findCurrentAdminRole, revokeAdminGrant as revokeAdminGrantInDb} from '#db/admin-grants.js';\nimport {hasMinimumAdminRole} from './admin-role-model.js';\nimport {AdminRoleRequiredError} from './errors.js';\n\nexport {ADMIN_ROLES, hasMinimumAdminRole, highestAdminRole} from './admin-role-model.js';\n\nexport async function getCurrentAdminRole(params: {userId: string}): Promise<AdminRole | null> {\n return await findCurrentAdminRole(params);\n}\n\nexport async function requireAdminRole(params: {\n userId: string;\n minimumRole: AdminRole;\n}): Promise<AdminRole> {\n const role = await getCurrentAdminRole({userId: params.userId});\n if (!role || !hasMinimumAdminRole(role, params.minimumRole)) {\n throw new AdminRoleRequiredError(params.minimumRole);\n }\n return role;\n}\n\nexport async function revokeAdminGrant(params: {grantId: string}) {\n return await revokeAdminGrantInDb(params);\n}\n"],"names":["findCurrentAdminRole","revokeAdminGrant","revokeAdminGrantInDb","hasMinimumAdminRole","AdminRoleRequiredError","ADMIN_ROLES","highestAdminRole","getCurrentAdminRole","params","requireAdminRole","role","userId","minimumRole"],"mappings":"AACA,SAAQA,oBAAoB,EAAEC,oBAAoBC,oBAAoB,QAAO,sBAAsB;AACnG,SAAQC,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,sBAAsB,QAAO,cAAc;AAEnD,SAAQC,WAAW,EAAEF,mBAAmB,EAAEG,gBAAgB,QAAO,wBAAwB;AAEzF,OAAO,eAAeC,oBAAoBC,MAAwB;IAChE,OAAO,MAAMR,qBAAqBQ;AACpC;AAEA,OAAO,eAAeC,iBAAiBD,MAGtC;IACC,MAAME,OAAO,MAAMH,oBAAoB;QAACI,QAAQH,OAAOG,MAAM;IAAA;IAC7D,IAAI,CAACD,QAAQ,CAACP,oBAAoBO,MAAMF,OAAOI,WAAW,GAAG;QAC3D,MAAM,IAAIR,uBAAuBI,OAAOI,WAAW;IACrD;IACA,OAAOF;AACT;AAEA,OAAO,eAAeT,iBAAiBO,MAAyB;IAC9D,OAAO,MAAMN,qBAAqBM;AACpC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AdminRole } from '@shipfox/api-auth-dto';
|
|
2
|
+
import type { AdminGrant } from './entities/admin-grant.js';
|
|
3
|
+
import { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError } from './errors.js';
|
|
4
|
+
export declare function hashAdministrationValue(value: string): string;
|
|
5
|
+
export declare function administrationCommandFingerprint(command: string, input: unknown): string;
|
|
6
|
+
export interface AdministrationMutationContext {
|
|
7
|
+
actorId: string;
|
|
8
|
+
idempotencyKey: string;
|
|
9
|
+
correlationId: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function bootstrapFirstAdminOwner(params: AdministrationMutationContext & {
|
|
12
|
+
bootstrapToken: string;
|
|
13
|
+
}): Promise<AdminGrant>;
|
|
14
|
+
export declare function listAdministratorGrants(params: {
|
|
15
|
+
actorId: string;
|
|
16
|
+
}): Promise<AdminGrant[]>;
|
|
17
|
+
export declare function grantAdministratorRole(params: AdministrationMutationContext & {
|
|
18
|
+
userId: string;
|
|
19
|
+
role: AdminRole;
|
|
20
|
+
reason: string;
|
|
21
|
+
}): Promise<AdminGrant>;
|
|
22
|
+
export declare function revokeAdministratorGrant(params: AdministrationMutationContext & {
|
|
23
|
+
grantId: string;
|
|
24
|
+
reason: string;
|
|
25
|
+
}): Promise<AdminGrant>;
|
|
26
|
+
export { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError, };
|
|
27
|
+
//# 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;AAUrD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,6BAA6B,EAC7B,+BAA+B,EAC/B,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAOrB,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,uBAAuB,CAAC,MAAM,EAAE;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAG9F;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,122 @@
|
|
|
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, listAdminGrants, revokeAdminGrantWithAudit } from '#db/admin-grants.js';
|
|
5
|
+
import { requireAdminRole } from './admin-role.js';
|
|
6
|
+
import { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError } from './errors.js';
|
|
7
|
+
const ADMIN_OWNER_ROLE = 'admin-owner';
|
|
8
|
+
const BOOTSTRAP_COMMAND = 'auth.admin_grant.bootstrap';
|
|
9
|
+
const GRANT_COMMAND = 'auth.admin_grant.grant';
|
|
10
|
+
const REVOKE_COMMAND = 'auth.admin_grant.revoke';
|
|
11
|
+
export function hashAdministrationValue(value) {
|
|
12
|
+
return createHash('sha256').update(value).digest('hex');
|
|
13
|
+
}
|
|
14
|
+
export function administrationCommandFingerprint(command, input) {
|
|
15
|
+
return hashAdministrationValue(`${command}:${JSON.stringify(input)}`);
|
|
16
|
+
}
|
|
17
|
+
function bootstrapTokenMatches(candidate, expected) {
|
|
18
|
+
if (!expected) return false;
|
|
19
|
+
const candidateHash = Buffer.from(hashAdministrationValue(candidate), 'hex');
|
|
20
|
+
const expectedHash = Buffer.from(hashAdministrationValue(expected), 'hex');
|
|
21
|
+
return timingSafeEqual(candidateHash, expectedHash);
|
|
22
|
+
}
|
|
23
|
+
function administrationEvent(params) {
|
|
24
|
+
return createAdministrationActionEvent({
|
|
25
|
+
actorId: params.actorId,
|
|
26
|
+
actorRole: params.actorRole,
|
|
27
|
+
requiredRole: ADMIN_OWNER_ROLE,
|
|
28
|
+
command: params.command,
|
|
29
|
+
targetType: params.targetType,
|
|
30
|
+
targetId: params.targetId,
|
|
31
|
+
reason: params.reason,
|
|
32
|
+
result: 'succeeded',
|
|
33
|
+
correlationId: params.correlationId,
|
|
34
|
+
idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,
|
|
35
|
+
occurredAt: new Date().toISOString()
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export async function bootstrapFirstAdminOwner(params) {
|
|
39
|
+
if (!bootstrapTokenMatches(params.bootstrapToken, config.ADMIN_BOOTSTRAP_TOKEN)) {
|
|
40
|
+
throw new InvalidAdminBootstrapTokenError();
|
|
41
|
+
}
|
|
42
|
+
return await bootstrapFirstAdminOwnerInDb({
|
|
43
|
+
userId: params.actorId,
|
|
44
|
+
actorId: params.actorId,
|
|
45
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
|
|
46
|
+
requestFingerprint: administrationCommandFingerprint(BOOTSTRAP_COMMAND, {
|
|
47
|
+
actorId: params.actorId
|
|
48
|
+
}),
|
|
49
|
+
event: administrationEvent({
|
|
50
|
+
actorId: params.actorId,
|
|
51
|
+
actorRole: ADMIN_OWNER_ROLE,
|
|
52
|
+
command: BOOTSTRAP_COMMAND,
|
|
53
|
+
targetType: 'user',
|
|
54
|
+
targetId: params.actorId,
|
|
55
|
+
reason: 'Initial administrator owner bootstrap',
|
|
56
|
+
correlationId: params.correlationId,
|
|
57
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export async function listAdministratorGrants(params) {
|
|
62
|
+
await requireAdminRole({
|
|
63
|
+
userId: params.actorId,
|
|
64
|
+
minimumRole: ADMIN_OWNER_ROLE
|
|
65
|
+
});
|
|
66
|
+
return await listAdminGrants();
|
|
67
|
+
}
|
|
68
|
+
export async function grantAdministratorRole(params) {
|
|
69
|
+
const actorRole = await requireAdminRole({
|
|
70
|
+
userId: params.actorId,
|
|
71
|
+
minimumRole: ADMIN_OWNER_ROLE
|
|
72
|
+
});
|
|
73
|
+
return await grantAdminRoleWithAudit({
|
|
74
|
+
userId: params.userId,
|
|
75
|
+
role: params.role,
|
|
76
|
+
actorId: params.actorId,
|
|
77
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
|
|
78
|
+
requestFingerprint: administrationCommandFingerprint(GRANT_COMMAND, {
|
|
79
|
+
userId: params.userId,
|
|
80
|
+
role: params.role,
|
|
81
|
+
reason: params.reason
|
|
82
|
+
}),
|
|
83
|
+
event: administrationEvent({
|
|
84
|
+
actorId: params.actorId,
|
|
85
|
+
actorRole,
|
|
86
|
+
command: GRANT_COMMAND,
|
|
87
|
+
targetType: 'user',
|
|
88
|
+
targetId: params.userId,
|
|
89
|
+
reason: params.reason,
|
|
90
|
+
correlationId: params.correlationId,
|
|
91
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
export async function revokeAdministratorGrant(params) {
|
|
96
|
+
const actorRole = await requireAdminRole({
|
|
97
|
+
userId: params.actorId,
|
|
98
|
+
minimumRole: ADMIN_OWNER_ROLE
|
|
99
|
+
});
|
|
100
|
+
return await revokeAdminGrantWithAudit({
|
|
101
|
+
grantId: params.grantId,
|
|
102
|
+
actorId: params.actorId,
|
|
103
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey),
|
|
104
|
+
requestFingerprint: administrationCommandFingerprint(REVOKE_COMMAND, {
|
|
105
|
+
grantId: params.grantId,
|
|
106
|
+
reason: params.reason
|
|
107
|
+
}),
|
|
108
|
+
event: administrationEvent({
|
|
109
|
+
actorId: params.actorId,
|
|
110
|
+
actorRole,
|
|
111
|
+
command: REVOKE_COMMAND,
|
|
112
|
+
targetType: 'admin-grant',
|
|
113
|
+
targetId: params.grantId,
|
|
114
|
+
reason: params.reason,
|
|
115
|
+
correlationId: params.correlationId,
|
|
116
|
+
idempotencyKeyFingerprint: hashAdministrationValue(params.idempotencyKey)
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
export { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError };
|
|
121
|
+
|
|
122
|
+
//# 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 {config} from '#config.js';\nimport {\n bootstrapFirstAdminOwner as bootstrapFirstAdminOwnerInDb,\n grantAdminRoleWithAudit,\n listAdminGrants,\n revokeAdminGrantWithAudit,\n} from '#db/admin-grants.js';\nimport {requireAdminRole} from './admin-role.js';\nimport type {AdminGrant} from './entities/admin-grant.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 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 listAdministratorGrants(params: {actorId: string}): Promise<AdminGrant[]> {\n await requireAdminRole({userId: params.actorId, minimumRole: ADMIN_OWNER_ROLE});\n return await listAdminGrants();\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","listAdminGrants","revokeAdminGrantWithAudit","requireAdminRole","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","InvalidAdminBootstrapTokenError","LastAdminOwnerError","UserNotFoundError","ADMIN_OWNER_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","listAdministratorGrants","minimumRole","grantAdministratorRole","role","revokeAdministratorGrant","grantId"],"mappings":"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"}
|
package/dist/core/auth.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { type AdminRole } from '@shipfox/api-auth-dto';
|
|
1
2
|
import { type WorkspacesInterModuleClient } from '@shipfox/api-workspaces-dto/inter-module';
|
|
2
3
|
import type { User } from './entities/user.js';
|
|
3
4
|
import { AuthDependencyUnavailableError, EmailNotVerifiedError, InvalidCredentialsError, UserNotFoundError } from './errors.js';
|
|
5
|
+
import type { SignupPolicy } from './ports.js';
|
|
4
6
|
export interface SignupParams {
|
|
5
7
|
email: string;
|
|
6
8
|
password: string;
|
|
7
9
|
name?: string | undefined;
|
|
10
|
+
signupPolicy?: SignupPolicy | undefined;
|
|
8
11
|
}
|
|
9
12
|
export interface ProvisionUserParams {
|
|
10
13
|
email: string;
|
|
11
14
|
name?: string | null | undefined;
|
|
15
|
+
signupPolicy?: SignupPolicy | undefined;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Creates a verified, password-less user for an external identity provider.
|
|
@@ -53,6 +57,7 @@ export interface LoginResult {
|
|
|
53
57
|
token: string;
|
|
54
58
|
refreshToken: string;
|
|
55
59
|
user: User;
|
|
60
|
+
adminRole: AdminRole | null;
|
|
56
61
|
}
|
|
57
62
|
export declare function login(params: LoginParams): Promise<LoginResult>;
|
|
58
63
|
export interface CreateSessionForUserParams {
|
|
@@ -64,6 +69,7 @@ export interface CreateSessionForUserResult {
|
|
|
64
69
|
token: string;
|
|
65
70
|
refreshToken: string;
|
|
66
71
|
user: User;
|
|
72
|
+
adminRole: AdminRole | null;
|
|
67
73
|
}
|
|
68
74
|
export type CreateSessionForUserError = AuthDependencyUnavailableError | EmailNotVerifiedError | InvalidCredentialsError | UserNotFoundError;
|
|
69
75
|
export declare function createSessionForUser(params: CreateSessionForUserParams): Promise<CreateSessionForUserResult>;
|
|
@@ -72,6 +78,7 @@ export interface RefreshAccessTokenResult {
|
|
|
72
78
|
/** Undefined on a grace-window hit: keep the existing cookie instead of rotating it. */
|
|
73
79
|
refreshToken: string | undefined;
|
|
74
80
|
user: User;
|
|
81
|
+
adminRole: AdminRole | null;
|
|
75
82
|
}
|
|
76
83
|
export declare function refreshAccessToken(params: {
|
|
77
84
|
refreshToken: string;
|
|
@@ -81,6 +88,7 @@ export interface ConfirmEmailVerificationResult {
|
|
|
81
88
|
token: string;
|
|
82
89
|
refreshToken: string;
|
|
83
90
|
user: User;
|
|
91
|
+
adminRole: AdminRole | null;
|
|
84
92
|
}
|
|
85
93
|
export interface ResendEmailVerificationResult {
|
|
86
94
|
nextResendAvailableAt: Date;
|
|
@@ -103,6 +111,7 @@ export interface ConfirmPasswordResetResult {
|
|
|
103
111
|
token: string;
|
|
104
112
|
refreshToken: string;
|
|
105
113
|
user: User;
|
|
114
|
+
adminRole: AdminRole | null;
|
|
106
115
|
}
|
|
107
116
|
export declare function confirmPasswordReset(params: {
|
|
108
117
|
token: string;
|
package/dist/core/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"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"}
|