@fuzdev/fuz_app 0.107.0 → 0.109.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/README.md +4 -0
- package/dist/actions/CLAUDE.md +1 -1
- package/dist/auth/CLAUDE.md +1 -1
- package/dist/auth/account_route_schema.d.ts +10 -1
- package/dist/auth/account_route_schema.d.ts.map +1 -1
- package/dist/auth/account_route_schema.js +10 -1
- package/dist/auth/account_routes.d.ts +18 -4
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +32 -29
- package/dist/auth/api_token_queries.d.ts +4 -0
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +5 -1
- package/dist/auth/audit_emitter.d.ts +9 -5
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.d.ts +7 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +16 -1
- package/dist/auth/bearer_auth.d.ts +9 -6
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +12 -21
- package/dist/auth/bootstrap_routes.d.ts +12 -2
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +26 -10
- package/dist/auth/middleware.d.ts +0 -3
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +11 -10
- package/dist/auth/migrations.d.ts +7 -0
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +45 -4
- package/dist/auth/session_queries.d.ts +13 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +14 -3
- package/dist/auth/signup_routes.d.ts +10 -0
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +14 -11
- package/dist/db/CLAUDE.md +9 -5
- package/dist/db/cell_audit_queries.d.ts +4 -2
- package/dist/db/cell_audit_queries.d.ts.map +1 -1
- package/dist/db/cell_audit_queries.js +4 -2
- package/dist/db/pg_error.d.ts +12 -0
- package/dist/db/pg_error.d.ts.map +1 -1
- package/dist/db/pg_error.js +15 -1
- package/dist/http/CLAUDE.md +78 -18
- package/dist/http/db_routes.d.ts +96 -3
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +263 -46
- package/dist/http/error_schemas.d.ts +13 -2
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +13 -2
- package/dist/http/pending_effects.d.ts +5 -5
- package/dist/http/pending_effects.d.ts.map +1 -1
- package/dist/http/pending_effects.js +1 -1
- package/dist/rate_limiter.d.ts +36 -3
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +36 -3
- package/dist/server/app_server.d.ts +27 -10
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +30 -20
- package/dist/server/app_server_context.d.ts +10 -2
- package/dist/server/app_server_context.d.ts.map +1 -1
- package/dist/testing/CLAUDE.md +42 -8
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +6 -4
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +5 -1
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.js +53 -1
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_spine_surface.js +9 -8
- package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
- package/dist/testing/cross_backend/login_security.js +59 -0
- package/dist/testing/cross_backend/query_shape.d.ts +10 -0
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -0
- package/dist/testing/cross_backend/query_shape.js +128 -0
- package/dist/testing/cross_backend/session_cap.d.ts +19 -0
- package/dist/testing/cross_backend/session_cap.d.ts.map +1 -0
- package/dist/testing/cross_backend/session_cap.js +93 -0
- package/dist/testing/middleware.d.ts +2 -5
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +5 -5
- package/dist/testing/rate_limiting.d.ts +10 -16
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +11 -95
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +3 -1
- package/dist/testing/testing_rate_limiter.d.ts +7 -1
- package/dist/testing/testing_rate_limiter.d.ts.map +1 -1
- package/dist/testing/testing_rate_limiter.js +7 -1
- package/dist/ui/CLAUDE.md +9 -4
- package/dist/ui/table_state.svelte.d.ts +18 -5
- package/dist/ui/table_state.svelte.d.ts.map +1 -1
- package/dist/ui/table_state.svelte.js +22 -7
- package/dist/ui/ui_format.d.ts.map +1 -1
- package/dist/ui/ui_format.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,6 +45,10 @@ Deno.serve({port: PORT, hostname: HOST}, app.fetch);
|
|
|
45
45
|
|
|
46
46
|
See [CLAUDE.md](CLAUDE.md) for more usage patterns and the AI-generated docs.
|
|
47
47
|
|
|
48
|
+
## Contributing
|
|
49
|
+
|
|
50
|
+
[fuz.dev/contributing](https://www.fuz.dev/contributing)
|
|
51
|
+
|
|
48
52
|
## License
|
|
49
53
|
|
|
50
54
|
[MIT](LICENSE)
|
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -217,7 +217,7 @@ ones. Matches the Rust spine, which validates handler-side.
|
|
|
217
217
|
|
|
218
218
|
Shim responsibilities (per-request):
|
|
219
219
|
|
|
220
|
-
1. Parse envelope (POST body / GET query string); parse errors → `parse_error` 400.
|
|
220
|
+
1. Parse envelope (POST body / GET query string); parse errors → `parse_error` 400. GET reads `method` / `id` / `params` via Hono's `c.req.query()` — first occurrence wins on a duplicated key, unknown keys are ignored, and an empty value counts as missing. This is the cross-impl contract (the Rust GET dispatch mirrors it via `fuz_http`'s `query_first`, including the id numeric-vs-string normalization), pinned by the `query_shape` cross suite.
|
|
221
221
|
2. Lookup method in the `compile_action_registry`-built map; unknown → `method_not_found`.
|
|
222
222
|
3. GET read restriction — GET rejected for `side_effects: true` actions.
|
|
223
223
|
4. Build `PerformActionInput` from `c.var` + `get_client_ip` + `c.req.raw.signal`. Test-preset escape hatch reads `TEST_CONTEXT_PRESET_KEY` + `REQUEST_CONTEXT_KEY`.
|
package/dist/auth/CLAUDE.md
CHANGED
|
@@ -379,7 +379,7 @@ token_create role_grant_offer_supersede
|
|
|
379
379
|
token_revoke invite_create
|
|
380
380
|
token_revoke_all invite_delete
|
|
381
381
|
account_delete app_settings_update
|
|
382
|
-
account_purge
|
|
382
|
+
account_purge db_admin_row_delete
|
|
383
383
|
account_undelete
|
|
384
384
|
actor_delete
|
|
385
385
|
actor_purge
|
|
@@ -79,7 +79,16 @@ export declare const PasswordChangeOutput: z.ZodObject<{
|
|
|
79
79
|
tokens_revoked: z.ZodNumber;
|
|
80
80
|
}, z.core.$strict>;
|
|
81
81
|
export type PasswordChangeOutput = z.infer<typeof PasswordChangeOutput>;
|
|
82
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Default maximum sessions per account.
|
|
84
|
+
*
|
|
85
|
+
* The Rust twin pins the same 5 as a `const` (`fuz_auth`'s
|
|
86
|
+
* `DEFAULT_MAX_SESSIONS`) rather than a route-state field, because its
|
|
87
|
+
* `AccountRouteState` has no `Default` and a new field would break every
|
|
88
|
+
* exhaustive literal in every consumer workspace. So this stays the
|
|
89
|
+
* configurable side of the pair (`null` disables), and the two ship the same
|
|
90
|
+
* number — retuning means editing both.
|
|
91
|
+
*/
|
|
83
92
|
export declare const DEFAULT_MAX_SESSIONS = 5;
|
|
84
93
|
/** Default maximum API tokens per account. */
|
|
85
94
|
export declare const DEFAULT_MAX_TOKENS = 10;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account_route_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_route_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQvD,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAC3C,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,4CAA4C;AAC5C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;kBAI9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC;;;iBAG5C,CAAC;AACH,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAElG,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;kBAGrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,6EAA6E;AAC7E,eAAO,MAAM,WAAW;;kBAEtB,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,2EAA2E;AAC3E,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,wFAAwF;AACxF,eAAO,MAAM,YAAY;;;kBAGvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD,sHAAsH;AACtH,eAAO,MAAM,mBAAmB;;;kBAG9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,uGAAuG;AACvG,eAAO,MAAM,oBAAoB;;;;kBAI/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE
|
|
1
|
+
{"version":3,"file":"account_route_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_route_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQvD,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAC3C,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,4CAA4C;AAC5C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;kBAI9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC;;;iBAG5C,CAAC;AACH,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAElG,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;kBAGrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,6EAA6E;AAC7E,eAAO,MAAM,WAAW;;kBAEtB,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,2EAA2E;AAC3E,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,wFAAwF;AACxF,eAAO,MAAM,YAAY;;;kBAGvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD,sHAAsH;AACtH,eAAO,MAAM,mBAAmB;;;kBAG9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,uGAAuG;AACvG,eAAO,MAAM,oBAAoB;;;;kBAI/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUD,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACxC,8FAA8F;IAC9F,0BAA0B,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,GACvC,SAAS,wBAAwB,KAC/B,CACF,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAC1B,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAC1B,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAC1B,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAoD1B,CAAC"}
|
|
@@ -56,7 +56,16 @@ export const PasswordChangeOutput = z.strictObject({
|
|
|
56
56
|
sessions_revoked: z.number(),
|
|
57
57
|
tokens_revoked: z.number()
|
|
58
58
|
});
|
|
59
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Default maximum sessions per account.
|
|
61
|
+
*
|
|
62
|
+
* The Rust twin pins the same 5 as a `const` (`fuz_auth`'s
|
|
63
|
+
* `DEFAULT_MAX_SESSIONS`) rather than a route-state field, because its
|
|
64
|
+
* `AccountRouteState` has no `Default` and a new field would break every
|
|
65
|
+
* exhaustive literal in every consumer workspace. So this stays the
|
|
66
|
+
* configurable side of the pair (`null` disables), and the two ship the same
|
|
67
|
+
* number — retuning means editing both.
|
|
68
|
+
*/
|
|
60
69
|
export const DEFAULT_MAX_SESSIONS = 5;
|
|
61
70
|
/** Default maximum API tokens per account. */
|
|
62
71
|
export const DEFAULT_MAX_TOKENS = 10;
|
|
@@ -69,20 +69,34 @@ export declare const DEFAULT_LOGIN_FAIL_FLOOR_MS = 250;
|
|
|
69
69
|
*/
|
|
70
70
|
export declare const DEFAULT_LOGIN_FAIL_JITTER_MS = 25;
|
|
71
71
|
/**
|
|
72
|
-
* Shared options for route factories that create sessions
|
|
72
|
+
* Shared options for route factories that create sessions.
|
|
73
73
|
*
|
|
74
74
|
* Extended by `AccountRouteOptions` and `SignupRouteOptions`.
|
|
75
75
|
* Consumers can destructure these from `AppServerContext` once and spread into multiple factories.
|
|
76
|
+
*
|
|
77
|
+
* The per-IP limiter is deliberately *not* here. Each auth surface names its
|
|
78
|
+
* own (`login_ip_rate_limiter`, `signup_ip_rate_limiter`,
|
|
79
|
+
* `bootstrap_ip_rate_limiter`) because the buckets are monotone within their
|
|
80
|
+
* window — see `RateLimiter.reset`. A shared base field made one instance the
|
|
81
|
+
* path of least resistance, which let a failure on any surface spend the
|
|
82
|
+
* budget that bounds guessing on every other one.
|
|
76
83
|
*/
|
|
77
84
|
export interface AuthSessionRouteOptions {
|
|
78
85
|
session_options: SessionOptions<string>;
|
|
79
|
-
/** Rate limiter for auth attempts, keyed by client IP. Pass `null` to disable. */
|
|
80
|
-
ip_rate_limiter: RateLimiter | null;
|
|
81
86
|
}
|
|
82
87
|
/**
|
|
83
88
|
* Per-factory configuration for account route specs.
|
|
84
89
|
*/
|
|
85
90
|
export interface AccountRouteOptions extends AuthSessionRouteOptions {
|
|
91
|
+
/**
|
|
92
|
+
* Rate limiter for login + password-change attempts, keyed by client IP.
|
|
93
|
+
* Pass `null` to disable. The distributed-spray backstop: login is the one
|
|
94
|
+
* surface that guesses *other* accounts' credentials, so this bucket is
|
|
95
|
+
* never refunded on success (see `RateLimiter.reset`). Password change
|
|
96
|
+
* shares it — it is password-bearing on the same account grain, and the
|
|
97
|
+
* Rust spine shares the same instance across both.
|
|
98
|
+
*/
|
|
99
|
+
login_ip_rate_limiter: RateLimiter | null;
|
|
86
100
|
/** Rate limiter for login attempts, keyed by submitted username. Pass `null` to disable. */
|
|
87
101
|
login_account_rate_limiter: RateLimiter | null;
|
|
88
102
|
/** Max active sessions per account. Evicts oldest on login. Default 5, `null` disables. */
|
|
@@ -130,7 +144,7 @@ export interface AccountRouteOptions extends AuthSessionRouteOptions {
|
|
|
130
144
|
* Self-service session/token management is on `auth/account_actions.ts`.
|
|
131
145
|
*
|
|
132
146
|
* @param deps - stateless capabilities (keyring, password, log)
|
|
133
|
-
* @param options - per-factory configuration (session_options,
|
|
147
|
+
* @param options - per-factory configuration (session_options, login_ip_rate_limiter, login_account_rate_limiter, bootstrap_status)
|
|
134
148
|
* @returns route specs (not yet applied to Hono)
|
|
135
149
|
*/
|
|
136
150
|
export declare const create_account_route_specs: (deps: RouteFactoryDeps, options: AccountRouteOptions) => Array<RouteSpec>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA4B1D,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGxE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,GAAI,UAAU,oBAAoB,KAAG,SA4EhF,CAAC;AAEH,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAQ/C
|
|
1
|
+
{"version":3,"file":"account_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA4B1D,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGxE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,GAAI,UAAU,oBAAoB,KAAG,SA4EhF,CAAC;AAEH,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAQ/C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,uBAAuB;IACvC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IACnE;;;;;;;OAOG;IACH,qBAAqB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1C,4FAA4F;IAC5F,0BAA0B,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC5C;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAID;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,GACtC,MAAM,gBAAgB,EACtB,SAAS,mBAAmB,KAC1B,KAAK,CAAC,SAAS,CA6RjB,CAAC"}
|
|
@@ -155,12 +155,12 @@ const login_fail_delay = (floor_ms, jitter_ms) => {
|
|
|
155
155
|
* Self-service session/token management is on `auth/account_actions.ts`.
|
|
156
156
|
*
|
|
157
157
|
* @param deps - stateless capabilities (keyring, password, log)
|
|
158
|
-
* @param options - per-factory configuration (session_options,
|
|
158
|
+
* @param options - per-factory configuration (session_options, login_ip_rate_limiter, login_account_rate_limiter, bootstrap_status)
|
|
159
159
|
* @returns route specs (not yet applied to Hono)
|
|
160
160
|
*/
|
|
161
161
|
export const create_account_route_specs = (deps, options) => {
|
|
162
162
|
const { keyring, password } = deps;
|
|
163
|
-
const { session_options,
|
|
163
|
+
const { session_options, login_ip_rate_limiter, login_account_rate_limiter, max_sessions = DEFAULT_MAX_SESSIONS, login_fail_floor_ms = DEFAULT_LOGIN_FAIL_FLOOR_MS, login_fail_jitter_ms = DEFAULT_LOGIN_FAIL_JITTER_MS, connection_closer = null, bootstrap_status } = options;
|
|
164
164
|
const [verify_shape, login_shape, logout_shape, password_shape] = create_account_route_shapes({
|
|
165
165
|
login_account_rate_limited: login_account_rate_limiter !== null
|
|
166
166
|
});
|
|
@@ -181,9 +181,9 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
181
181
|
...login_shape,
|
|
182
182
|
handler: async (c, route) => {
|
|
183
183
|
// Per-IP rate limit check (before any DB/password work)
|
|
184
|
-
const ip =
|
|
185
|
-
if (
|
|
186
|
-
const check =
|
|
184
|
+
const ip = login_ip_rate_limiter ? get_client_ip(c) : null;
|
|
185
|
+
if (login_ip_rate_limiter && ip) {
|
|
186
|
+
const check = login_ip_rate_limiter.check(ip);
|
|
187
187
|
if (!check.allowed) {
|
|
188
188
|
return rate_limit_exceeded_response(c, check.retry_after);
|
|
189
189
|
}
|
|
@@ -214,8 +214,8 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
214
214
|
// enumeration prevention: verify_dummy equalizes Argon2id timing;
|
|
215
215
|
// login_fail_delay equalizes every other path difference.
|
|
216
216
|
await password.verify_dummy(pw);
|
|
217
|
-
if (
|
|
218
|
-
|
|
217
|
+
if (login_ip_rate_limiter && ip)
|
|
218
|
+
login_ip_rate_limiter.record(ip);
|
|
219
219
|
if (login_account_rate_limiter)
|
|
220
220
|
login_account_rate_limiter.record(account_rate_key);
|
|
221
221
|
deps.audit.emit(route, {
|
|
@@ -229,8 +229,8 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
229
229
|
}
|
|
230
230
|
const valid = await password.verify_password(pw, account.password_hash);
|
|
231
231
|
if (!valid) {
|
|
232
|
-
if (
|
|
233
|
-
|
|
232
|
+
if (login_ip_rate_limiter && ip)
|
|
233
|
+
login_ip_rate_limiter.record(ip);
|
|
234
234
|
if (login_account_rate_limiter)
|
|
235
235
|
login_account_rate_limiter.record(account_rate_key);
|
|
236
236
|
deps.audit.emit(route, {
|
|
@@ -243,9 +243,11 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
243
243
|
await delay;
|
|
244
244
|
return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
|
|
245
245
|
}
|
|
246
|
-
// Successful login —
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
// Successful login — clear the account-grain failure history only.
|
|
247
|
+
// The IP aggregate is deliberately left standing: it is the
|
|
248
|
+
// distributed-spray backstop, so a success on one account must not
|
|
249
|
+
// refund the budget shared by every other account reachable from
|
|
250
|
+
// that address. See `RateLimiter.reset`.
|
|
249
251
|
if (login_account_rate_limiter)
|
|
250
252
|
login_account_rate_limiter.reset(account_rate_key);
|
|
251
253
|
await create_session_and_set_cookie({
|
|
@@ -305,9 +307,9 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
305
307
|
...password_shape,
|
|
306
308
|
handler: async (c, route) => {
|
|
307
309
|
// per-IP rate limit check (before argon2 work)
|
|
308
|
-
const ip =
|
|
309
|
-
if (
|
|
310
|
-
const check =
|
|
310
|
+
const ip = login_ip_rate_limiter ? get_client_ip(c) : null;
|
|
311
|
+
if (login_ip_rate_limiter && ip) {
|
|
312
|
+
const check = login_ip_rate_limiter.check(ip);
|
|
311
313
|
if (!check.allowed) {
|
|
312
314
|
return rate_limit_exceeded_response(c, check.retry_after);
|
|
313
315
|
}
|
|
@@ -325,8 +327,8 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
325
327
|
}
|
|
326
328
|
const valid = await password.verify_password(current_password, ctx.account.password_hash);
|
|
327
329
|
if (!valid) {
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
+
if (login_ip_rate_limiter && ip)
|
|
331
|
+
login_ip_rate_limiter.record(ip);
|
|
330
332
|
if (login_account_rate_limiter)
|
|
331
333
|
login_account_rate_limiter.record(ctx.account.id);
|
|
332
334
|
deps.audit.emit(route, {
|
|
@@ -350,16 +352,17 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
350
352
|
// incidental; password is account-level state).
|
|
351
353
|
const updated = await query_update_account_password(route, ctx.account.id, new_hash, null, ctx.account.password_hash);
|
|
352
354
|
// Verify-success contract — the caller proved knowledge, so wipe
|
|
353
|
-
// their failure history. The race-loser branch below
|
|
354
|
-
// one on top of the wiped slate so net cost stays 1
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
355
|
+
// their account-grain failure history. The race-loser branch below
|
|
356
|
+
// re-records one on top of the wiped slate so net cost stays 1 on
|
|
357
|
+
// that bucket. Deferring from "after verify" to "after UPDATE
|
|
358
|
+
// settled" is what closes the S1 bypass — a throw between reset
|
|
359
|
+
// and the UPDATE could have wiped an attacker's budget.
|
|
360
|
+
//
|
|
361
|
+
// The IP aggregate is deliberately not cleared: it is the same
|
|
362
|
+
// instance login uses, so refunding it here reopens the spray path
|
|
363
|
+
// through a route that only needs the caller's *own* password. Its
|
|
364
|
+
// record on the race-loser branch below therefore accumulates
|
|
365
|
+
// rather than netting out, which is the intent.
|
|
363
366
|
if (login_account_rate_limiter)
|
|
364
367
|
login_account_rate_limiter.reset(ctx.account.id);
|
|
365
368
|
if (!updated) {
|
|
@@ -370,8 +373,8 @@ export const create_account_route_specs = (deps, options) => {
|
|
|
370
373
|
// audit log can distinguish "user typoed" from "two clients
|
|
371
374
|
// raced." Sessions/tokens were already revoked by the winner;
|
|
372
375
|
// no cookie clear here either.
|
|
373
|
-
if (
|
|
374
|
-
|
|
376
|
+
if (login_ip_rate_limiter && ip)
|
|
377
|
+
login_ip_rate_limiter.record(ip);
|
|
375
378
|
if (login_account_rate_limiter)
|
|
376
379
|
login_account_rate_limiter.record(ctx.account.id);
|
|
377
380
|
deps.audit.emit(route, {
|
|
@@ -82,6 +82,10 @@ export declare const query_api_token_list_for_account: (deps: QueryDeps, account
|
|
|
82
82
|
* `(account_id, credential_kind)` before count/evict/insert — see the matching
|
|
83
83
|
* note on `query_session_enforce_limit`.
|
|
84
84
|
*
|
|
85
|
+
* Ordering carries the same `id DESC` stability tie-breaker, with the same
|
|
86
|
+
* caveat, as `query_session_enforce_limit` — deterministic survivors under a
|
|
87
|
+
* `created_at` tie, not a guarantee that the row just inserted survives.
|
|
88
|
+
*
|
|
85
89
|
* @param deps - query dependencies (must be transaction-scoped)
|
|
86
90
|
* @param account_id - the account to enforce the limit for
|
|
87
91
|
* @param max_tokens - maximum number of tokens to keep
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,KAAK,UAAU,EAAmD,MAAM,kBAAkB,CAAC;AAEpG,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,EAClB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAO,UAAU,EACjB,aAAa,IAAI,GAAG,IAAI,KACtB,OAAO,CAAC,QAAQ,CAelB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,iBAAiB,EACvB,WAAW,MAAM,EACjB,IAAI,MAAM,GAAG,SAAS,EACtB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,KAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAgC9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAM7C,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,KAAK,UAAU,EAAmD,MAAM,kBAAkB,CAAC;AAEpG,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,EAClB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAO,UAAU,EACjB,aAAa,IAAI,GAAG,IAAI,KACtB,OAAO,CAAC,QAAQ,CAelB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,iBAAiB,EACvB,WAAW,MAAM,EACjB,IAAI,MAAM,GAAG,SAAS,EACtB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,KAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAgC9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAM7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAYhB,CAAC"}
|
|
@@ -125,6 +125,10 @@ export const query_api_token_list_for_account = async (deps, account_id) => {
|
|
|
125
125
|
* `(account_id, credential_kind)` before count/evict/insert — see the matching
|
|
126
126
|
* note on `query_session_enforce_limit`.
|
|
127
127
|
*
|
|
128
|
+
* Ordering carries the same `id DESC` stability tie-breaker, with the same
|
|
129
|
+
* caveat, as `query_session_enforce_limit` — deterministic survivors under a
|
|
130
|
+
* `created_at` tie, not a guarantee that the row just inserted survives.
|
|
131
|
+
*
|
|
128
132
|
* @param deps - query dependencies (must be transaction-scoped)
|
|
129
133
|
* @param account_id - the account to enforce the limit for
|
|
130
134
|
* @param max_tokens - maximum number of tokens to keep
|
|
@@ -136,7 +140,7 @@ export const query_api_token_enforce_limit = async (deps, account_id, max_tokens
|
|
|
136
140
|
WHERE id IN (
|
|
137
141
|
SELECT id FROM api_token
|
|
138
142
|
WHERE account_id = $1
|
|
139
|
-
ORDER BY created_at DESC
|
|
143
|
+
ORDER BY created_at DESC, id DESC
|
|
140
144
|
OFFSET $2
|
|
141
145
|
) RETURNING id`, [account_id, max_tokens]);
|
|
142
146
|
return rows.length;
|
|
@@ -49,12 +49,16 @@ import { type AuditLogConfig, type AuditLogEvent, type AuditLogInput } from './a
|
|
|
49
49
|
* `pending_effects` queue. The bound emitter carries its own `log`
|
|
50
50
|
* reference inside the closure, so per-call contexts don't need one.
|
|
51
51
|
*
|
|
52
|
-
* Audit emits are eager
|
|
52
|
+
* Audit emits are eager by default: the bound emitter fires the
|
|
53
53
|
* pool write immediately and pushes the in-flight `Promise<void>` here.
|
|
54
|
-
*
|
|
55
|
-
* are already rollback-resilient because they run
|
|
56
|
-
* transaction, so
|
|
57
|
-
*
|
|
54
|
+
* Attempt/failure audits never go through `emit_after_commit` —
|
|
55
|
+
* pool-routed writes are already rollback-resilient because they run
|
|
56
|
+
* outside the request transaction, so deferring them would only delay
|
|
57
|
+
* forensic visibility without any safety benefit. The exception is a
|
|
58
|
+
* **success-only** event paired with a state mutation (the
|
|
59
|
+
* `db_admin_row_delete` emit in `http/db_routes.ts`): there the caller
|
|
60
|
+
* wraps the emit in `emit_after_commit` so the trail can't claim a
|
|
61
|
+
* mutation whose transaction failed at COMMIT.
|
|
58
62
|
*
|
|
59
63
|
* Both `RouteContext` and `ActionContext` structurally satisfy this
|
|
60
64
|
* shape (they each carry `pending_effects`), so handlers pass `route`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_emitter.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,uBAAuB,CAAC;AAE/B
|
|
1
|
+
{"version":3,"file":"audit_emitter.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,mBAAmB;IACnC,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACrE,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAChF;;;;;;;OAOG;IACH,sBAAsB,CAAC,CAAC,SAAS,MAAM,EACtC,GAAG,EAAE,yBAAyB,EAC9B,IAAI,EAAE,mBAAmB,EACzB,KAAK,EAAE;QACN,UAAU,EAAE,CAAC,CAAC;QACd,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;QAC/B,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;QAC7B,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACvC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;KAChC,GACC,IAAI,CAAC;IACR;;;;;;;;;;OAUG;IACH,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7D,+EAA+E;IAC/E,cAAc,IAAI,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,SAAS,MAAM,EAC1C,GAAG,EAAE,mBAAmB,EACxB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KACnB,IAAI,CAAC;AAEV;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,WAAW,CAAC;AAEhE,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACzC,oDAAoD;IACpD,EAAE,EAAE,EAAE,CAAC;IACP,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,yBAAyB,KAAG,YAuFzE,CAAC"}
|
|
@@ -16,7 +16,7 @@ import { Uuid } from '@fuzdev/fuz_util/id.ts';
|
|
|
16
16
|
* Not a security boundary — in-process code has many other paths to subvert
|
|
17
17
|
* audit logging.
|
|
18
18
|
*/
|
|
19
|
-
export declare const AUDIT_EVENT_TYPES: readonly ["login", "logout", "bootstrap", "signup", "password_change", "session_revoke", "session_revoke_all", "token_create", "token_revoke", "token_revoke_all", "role_grant_create", "role_grant_revoke", "role_grant_offer_create", "role_grant_offer_accept", "role_grant_offer_decline", "role_grant_offer_retract", "role_grant_offer_expire", "role_grant_offer_supersede", "invite_create", "invite_delete", "account_delete", "account_purge", "account_undelete", "actor_delete", "actor_purge", "actor_undelete", "app_settings_update"];
|
|
19
|
+
export declare const AUDIT_EVENT_TYPES: readonly ["login", "logout", "bootstrap", "signup", "password_change", "session_revoke", "session_revoke_all", "token_create", "token_revoke", "token_revoke_all", "role_grant_create", "role_grant_revoke", "role_grant_offer_create", "role_grant_offer_accept", "role_grant_offer_decline", "role_grant_offer_retract", "role_grant_offer_expire", "role_grant_offer_supersede", "invite_create", "invite_delete", "account_delete", "account_purge", "account_undelete", "actor_delete", "actor_purge", "actor_undelete", "app_settings_update", "db_admin_row_delete"];
|
|
20
20
|
/** Zod schema for audit event types. */
|
|
21
21
|
export declare const AuditEventType: z.ZodEnum<{
|
|
22
22
|
bootstrap: "bootstrap";
|
|
@@ -46,6 +46,7 @@ export declare const AuditEventType: z.ZodEnum<{
|
|
|
46
46
|
actor_purge: "actor_purge";
|
|
47
47
|
actor_undelete: "actor_undelete";
|
|
48
48
|
app_settings_update: "app_settings_update";
|
|
49
|
+
db_admin_row_delete: "db_admin_row_delete";
|
|
49
50
|
}>;
|
|
50
51
|
export type AuditEventType = z.infer<typeof AuditEventType>;
|
|
51
52
|
/**
|
|
@@ -230,6 +231,11 @@ export declare const audit_metadata_schemas: Readonly<{
|
|
|
230
231
|
old_value: z.ZodUnknown;
|
|
231
232
|
new_value: z.ZodUnknown;
|
|
232
233
|
}, z.core.$loose>;
|
|
234
|
+
db_admin_row_delete: z.ZodObject<{
|
|
235
|
+
table: z.ZodString;
|
|
236
|
+
pk_column: z.ZodString;
|
|
237
|
+
id: z.ZodString;
|
|
238
|
+
}, z.core.$loose>;
|
|
233
239
|
}>;
|
|
234
240
|
/** Mapped type of metadata shapes per event type, derived from Zod schemas. */
|
|
235
241
|
export type AuditMetadataMap = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAmB9C;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,7 +57,8 @@ export const AUDIT_EVENT_TYPES = Object.freeze([
|
|
|
57
57
|
'actor_delete',
|
|
58
58
|
'actor_purge',
|
|
59
59
|
'actor_undelete',
|
|
60
|
-
'app_settings_update'
|
|
60
|
+
'app_settings_update',
|
|
61
|
+
'db_admin_row_delete'
|
|
61
62
|
]);
|
|
62
63
|
/** Zod schema for audit event types. */
|
|
63
64
|
export const AuditEventType = z.enum(AUDIT_EVENT_TYPES);
|
|
@@ -344,6 +345,20 @@ export const audit_metadata_schemas = Object.freeze({
|
|
|
344
345
|
setting: z.string().meta({ description: 'Name of the setting that changed.' }),
|
|
345
346
|
old_value: z.unknown().meta({ description: 'Setting value before the update.' }),
|
|
346
347
|
new_value: z.unknown().meta({ description: 'Setting value after the update.' })
|
|
348
|
+
}),
|
|
349
|
+
// Row deleted through the generic db-admin table browser
|
|
350
|
+
// (`http/db_routes.ts` / the Rust spine's `fuz_db_admin`). Account-grain
|
|
351
|
+
// attribution (`account_id`, no `actor_id`) — the browser's gate is
|
|
352
|
+
// account-grain by construction. Emitted only on a successful delete;
|
|
353
|
+
// post-composite-refusal the delete is provably single-row, so no count.
|
|
354
|
+
db_admin_row_delete: z.looseObject({
|
|
355
|
+
table: z.string().meta({ description: 'Table the row was deleted from.' }),
|
|
356
|
+
pk_column: z.string().meta({
|
|
357
|
+
description: 'Single primary-key column the `DELETE` filtered on.'
|
|
358
|
+
}),
|
|
359
|
+
id: z.string().meta({
|
|
360
|
+
description: "Primary-key value of the deleted row, as the row's canonical `::text` rendering."
|
|
361
|
+
})
|
|
347
362
|
})
|
|
348
363
|
});
|
|
349
364
|
/**
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
import type { MiddlewareHandler } from 'hono';
|
|
18
18
|
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
19
19
|
import type { QueryDeps } from '../db/query_deps.js';
|
|
20
|
-
import { type RateLimiter } from '../rate_limiter.js';
|
|
21
20
|
/**
|
|
22
21
|
* Create middleware that authenticates via bearer token.
|
|
23
22
|
*
|
|
@@ -37,14 +36,18 @@ import { type RateLimiter } from '../rate_limiter.js';
|
|
|
37
36
|
* (e.g. by session middleware). Acting-actor resolution + `RequestContext`
|
|
38
37
|
* construction are deferred to the dispatcher's authorization phase.
|
|
39
38
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* There is deliberately **no rate limit on this path**, and no 429 — every
|
|
40
|
+
* failure soft-fails to "no credential". An API token is 32 bytes of CSPRNG
|
|
41
|
+
* output resolved by a blake3 hash lookup, so guessing is bounded by entropy,
|
|
42
|
+
* not by throttling; a limiter here would buy nothing measurable while costing
|
|
43
|
+
* availability (the check/record has to precede the async lookup to close its
|
|
44
|
+
* own TOCTOU window, so concurrent requests bearing a *valid* token race each
|
|
45
|
+
* other into a 429). The Rust spine never had one here; this is the converged
|
|
46
|
+
* shape. See `docs/security.md` §Why bearer auth is not rate limited.
|
|
42
47
|
*
|
|
43
48
|
* @param deps - query dependencies (pool-level db for middleware)
|
|
44
|
-
* @param ip_rate_limiter - per-IP rate limiter for bearer token attempts (null to disable)
|
|
45
49
|
* @param log - the logger instance
|
|
46
50
|
* @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
|
|
47
|
-
* @mutates `ip_rate_limiter` - records on attempt; resets on a valid token
|
|
48
51
|
*/
|
|
49
|
-
export declare const create_bearer_auth_middleware: (deps: QueryDeps,
|
|
52
|
+
export declare const create_bearer_auth_middleware: (deps: QueryDeps, log: Logger) => MiddlewareHandler;
|
|
50
53
|
//# sourceMappingURL=bearer_auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,6BAA6B,GAAI,MAAM,SAAS,EAAE,KAAK,MAAM,KAAG,iBAuE5E,CAAC"}
|
package/dist/auth/bearer_auth.js
CHANGED
|
@@ -20,7 +20,6 @@ import { parse_stored_token_scope, token_scope_full } from './token_scope.js';
|
|
|
20
20
|
import { query_validate_api_token } from './api_token_queries.js';
|
|
21
21
|
import { get_client_ip } from '../http/client_ip.js';
|
|
22
22
|
import { is_browser_context } from '../http/origin.js';
|
|
23
|
-
import { rate_limit_exceeded_response } from '../rate_limiter.js';
|
|
24
23
|
/**
|
|
25
24
|
* Create middleware that authenticates via bearer token.
|
|
26
25
|
*
|
|
@@ -40,16 +39,20 @@ import { rate_limit_exceeded_response } from '../rate_limiter.js';
|
|
|
40
39
|
* (e.g. by session middleware). Acting-actor resolution + `RequestContext`
|
|
41
40
|
* construction are deferred to the dispatcher's authorization phase.
|
|
42
41
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* There is deliberately **no rate limit on this path**, and no 429 — every
|
|
43
|
+
* failure soft-fails to "no credential". An API token is 32 bytes of CSPRNG
|
|
44
|
+
* output resolved by a blake3 hash lookup, so guessing is bounded by entropy,
|
|
45
|
+
* not by throttling; a limiter here would buy nothing measurable while costing
|
|
46
|
+
* availability (the check/record has to precede the async lookup to close its
|
|
47
|
+
* own TOCTOU window, so concurrent requests bearing a *valid* token race each
|
|
48
|
+
* other into a 429). The Rust spine never had one here; this is the converged
|
|
49
|
+
* shape. See `docs/security.md` §Why bearer auth is not rate limited.
|
|
45
50
|
*
|
|
46
51
|
* @param deps - query dependencies (pool-level db for middleware)
|
|
47
|
-
* @param ip_rate_limiter - per-IP rate limiter for bearer token attempts (null to disable)
|
|
48
52
|
* @param log - the logger instance
|
|
49
53
|
* @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, and `AUTH_API_TOKEN_ID_KEY` on success
|
|
50
|
-
* @mutates `ip_rate_limiter` - records on attempt; resets on a valid token
|
|
51
54
|
*/
|
|
52
|
-
export const create_bearer_auth_middleware = (deps,
|
|
55
|
+
export const create_bearer_auth_middleware = (deps, log) => {
|
|
53
56
|
return async (c, next) => {
|
|
54
57
|
// Skip if an account is already authenticated (e.g. by session middleware)
|
|
55
58
|
if (c.get(ACCOUNT_ID_KEY) != null) {
|
|
@@ -88,28 +91,16 @@ export const create_bearer_auth_middleware = (deps, ip_rate_limiter, log) => {
|
|
|
88
91
|
await next();
|
|
89
92
|
return;
|
|
90
93
|
}
|
|
94
|
+
// `ip` feeds the token's `last_used_ip` bookkeeping, not a limiter.
|
|
91
95
|
const ip = get_client_ip(c);
|
|
92
|
-
// Per-IP rate limit: record before async DB work to close the TOCTOU
|
|
93
|
-
// window where concurrent requests could all pass check() before any
|
|
94
|
-
// reaches record(). On valid token, reset the counter below.
|
|
95
|
-
if (ip_rate_limiter) {
|
|
96
|
-
const check = ip_rate_limiter.check(ip);
|
|
97
|
-
if (!check.allowed) {
|
|
98
|
-
return rate_limit_exceeded_response(c, check.retry_after);
|
|
99
|
-
}
|
|
100
|
-
ip_rate_limiter.record(ip);
|
|
101
|
-
}
|
|
102
96
|
const api_token = await query_validate_api_token({ ...deps, log }, raw_token, ip, c.var.pending_effects);
|
|
103
97
|
if (!api_token) {
|
|
104
|
-
// Invalid or expired token — soft-fail
|
|
105
|
-
//
|
|
98
|
+
// Invalid or expired token — soft-fail, indistinguishable from
|
|
99
|
+
// sending no credential at all.
|
|
106
100
|
log.debug('bearer auth soft-fail: token not found or expired');
|
|
107
101
|
await next();
|
|
108
102
|
return;
|
|
109
103
|
}
|
|
110
|
-
// Valid token — reset rate limit counter
|
|
111
|
-
if (ip_rate_limiter)
|
|
112
|
-
ip_rate_limiter.reset(ip);
|
|
113
104
|
c.set(ACCOUNT_ID_KEY, api_token.account_id);
|
|
114
105
|
c.set(CREDENTIAL_TYPE_KEY, 'api_token');
|
|
115
106
|
c.set(AUTH_API_TOKEN_ID_KEY, api_token.id);
|
|
@@ -37,8 +37,18 @@ export interface BootstrapRouteOptions {
|
|
|
37
37
|
* Use for app-specific post-bootstrap work like generating API tokens.
|
|
38
38
|
*/
|
|
39
39
|
on_bootstrap?: (result: BootstrapAccountSuccess, c: Context) => Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Rate limiter for bootstrap attempts, keyed by client IP. Pass `null` to
|
|
42
|
+
* disable. Its own instance, not login's: bootstrap is one-shot and its
|
|
43
|
+
* bucket is never refunded on success (see `RateLimiter.reset`), so a
|
|
44
|
+
* fumbled token would otherwise leave the operator's *login* budget nearly
|
|
45
|
+
* spent on a deployment where their new account is the only one that
|
|
46
|
+
* exists. The Rust spine rate-limits bootstrap not at all (the token is
|
|
47
|
+
* 32 bytes of CSPRNG compared in constant time); this is the tighter side
|
|
48
|
+
* of that divergence, kept because the token also sits in a file whose
|
|
49
|
+
* read path an operator can misconfigure.
|
|
50
|
+
*/
|
|
51
|
+
bootstrap_ip_rate_limiter: RateLimiter | null;
|
|
42
52
|
}
|
|
43
53
|
/**
|
|
44
54
|
* Dependencies for checking bootstrap status at startup.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,gBAAgB,EAAE,eAAe,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E
|
|
1
|
+
{"version":3,"file":"bootstrap_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,gBAAgB,EAAE,eAAe,CAAC;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E;;;;;;;;;;OAUG;IACH,yBAAyB,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,EAAE,EAAE,EAAE,CAAC;IACP,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,wBAAwB,EAC9B,SAAS;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,KACpC,OAAO,CAAC,eAAe,CAwBzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,gBAAgB,EACtB,SAAS,qBAAqB,KAC5B,KAAK,CAAC,SAAS,CAmHjB,CAAC"}
|