@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/dist/rate_limiter.js
CHANGED
|
@@ -16,7 +16,18 @@ import { ERROR_RATE_LIMIT_EXCEEDED } from './http/error_schemas.js';
|
|
|
16
16
|
* MB in the worst case.
|
|
17
17
|
*/
|
|
18
18
|
export const DEFAULT_RATE_LIMITER_MAX_KEYS = 100_000;
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Default options for per-IP auth rate limiting: 5 attempts per 15 minutes.
|
|
21
|
+
* The default for each of the three per-surface IP limiters (login + password
|
|
22
|
+
* change, signup, bootstrap) and the shared cap the Rust spine's
|
|
23
|
+
* `DEFAULT_LOGIN_IP_RATE_LIMIT` pins.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately **not** widened when the buckets became monotone (a success no
|
|
26
|
+
* longer refunds them — see `RateLimiter.reset`). Widening would have bought
|
|
27
|
+
* NAT'd egress headroom by loosening the one bound that caps credential
|
|
28
|
+
* guessing from a single address; splitting one shared bucket into three
|
|
29
|
+
* per-surface ones buys the same headroom without touching that bound.
|
|
30
|
+
*/
|
|
20
31
|
export const default_login_ip_rate_limit = {
|
|
21
32
|
max_attempts: 5,
|
|
22
33
|
window_ms: 15 * 60_000,
|
|
@@ -69,7 +80,7 @@ export const default_action_account_rate_limit = {
|
|
|
69
80
|
* key-enumeration attack at the cost of a slight per-op overhead and the
|
|
70
81
|
* LRU trade-off described on `RateLimiterOptions.max_keys`.
|
|
71
82
|
*
|
|
72
|
-
* Parameters that accept `RateLimiter | null` (e.g. `
|
|
83
|
+
* Parameters that accept `RateLimiter | null` (e.g. `login_ip_rate_limiter`,
|
|
73
84
|
* `login_account_rate_limiter`) silently disable rate limiting when `null`
|
|
74
85
|
* is passed — no checks are performed and all requests are allowed through.
|
|
75
86
|
*/
|
|
@@ -170,7 +181,29 @@ export class RateLimiter {
|
|
|
170
181
|
return { allowed: false, remaining: 0, retry_after };
|
|
171
182
|
}
|
|
172
183
|
/**
|
|
173
|
-
* Clear all attempts for `key
|
|
184
|
+
* Clear all attempts for `key`.
|
|
185
|
+
*
|
|
186
|
+
* **Account-grain keys only.** Called after a successful auth to forgive a
|
|
187
|
+
* user's own typos, which is safe because the key *is* the account being
|
|
188
|
+
* attacked — clearing it requires that account's credential and can only
|
|
189
|
+
* widen the budget against an account the caller already holds.
|
|
190
|
+
*
|
|
191
|
+
* Never call this on an **IP-aggregate** key. That bucket is the
|
|
192
|
+
* distributed-spray backstop, and success on one account must not zero the
|
|
193
|
+
* budget shared by every other account reachable from the same IP;
|
|
194
|
+
* otherwise an attacker interleaves their own logins (or, under open signup,
|
|
195
|
+
* throwaway account creations needing no credential at all) with guesses
|
|
196
|
+
* against arbitrary victims and sprays indefinitely from one address.
|
|
197
|
+
* Nothing records on the IP bucket on success on any path, so with no reset
|
|
198
|
+
* it is a pure monotone-within-window failure counter that only time clears.
|
|
199
|
+
*
|
|
200
|
+
* Because they are monotone, the IP buckets are **one instance per auth
|
|
201
|
+
* surface** (`login_ip_rate_limiter`, `signup_ip_rate_limiter`,
|
|
202
|
+
* `bootstrap_ip_rate_limiter`) rather than one shared across all of them.
|
|
203
|
+
* A single instance meant a failure on any surface spent the budget that
|
|
204
|
+
* bounds guessing on every other one, and one caller's exhaustion denied
|
|
205
|
+
* four routes at once — a cost that used to be masked by the reset this
|
|
206
|
+
* doc forbids.
|
|
174
207
|
*
|
|
175
208
|
* @mutates internal map - removes the entry for `key`
|
|
176
209
|
*/
|
|
@@ -95,12 +95,35 @@ export interface AppServerOptions {
|
|
|
95
95
|
get_connection_ip: (c: Context) => string | undefined;
|
|
96
96
|
};
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
99
|
-
* Omit or `undefined` to use a default limiter (5 attempts per
|
|
100
|
-
* Pass `null` to explicitly disable rate limiting.
|
|
98
|
+
* Per-IP rate limiter for login + password change — the distributed-spray
|
|
99
|
+
* backstop. Omit or `undefined` to use a default limiter (5 attempts per
|
|
100
|
+
* 15 minutes). Pass `null` to explicitly disable rate limiting.
|
|
101
101
|
* Also available on `AppServerContext` for route factory callbacks.
|
|
102
|
+
*
|
|
103
|
+
* One instance per auth surface, not one shared across all four. These
|
|
104
|
+
* buckets are monotone within their window — a success never refunds them
|
|
105
|
+
* (see `RateLimiter.reset`) — so a shared instance let a failure on any
|
|
106
|
+
* surface spend the budget that bounds guessing on every other one, and
|
|
107
|
+
* let one caller's exhaustion deny four routes at once. Pass the same
|
|
108
|
+
* limiter to two of these fields to opt back into a shared budget.
|
|
102
109
|
*/
|
|
103
|
-
|
|
110
|
+
login_ip_rate_limiter?: RateLimiter | null;
|
|
111
|
+
/**
|
|
112
|
+
* Per-IP rate limiter for signup. Omit or `undefined` to use a default
|
|
113
|
+
* limiter (5 attempts per 15 minutes). Pass `null` to explicitly disable.
|
|
114
|
+
* Separate from `login_ip_rate_limiter` because an open-signup deployment
|
|
115
|
+
* lets any unauthenticated caller spend it. Also available on
|
|
116
|
+
* `AppServerContext` for route factory callbacks.
|
|
117
|
+
*/
|
|
118
|
+
signup_ip_rate_limiter?: RateLimiter | null;
|
|
119
|
+
/**
|
|
120
|
+
* Per-IP rate limiter for bootstrap. Omit or `undefined` to use a default
|
|
121
|
+
* limiter (5 attempts per 15 minutes). Pass `null` to explicitly disable.
|
|
122
|
+
* Separate from `login_ip_rate_limiter` so a fumbled bootstrap token can't
|
|
123
|
+
* spend the operator's login budget. Wired directly into the factory-managed
|
|
124
|
+
* bootstrap route; also on `AppServerContext` for symmetry.
|
|
125
|
+
*/
|
|
126
|
+
bootstrap_ip_rate_limiter?: RateLimiter | null;
|
|
104
127
|
/**
|
|
105
128
|
* Per-account rate limiter for login attempts.
|
|
106
129
|
* Omit or `undefined` to use a default limiter (10 attempts per 30 minutes).
|
|
@@ -115,12 +138,6 @@ export interface AppServerOptions {
|
|
|
115
138
|
* Also available on `AppServerContext` for route factory callbacks.
|
|
116
139
|
*/
|
|
117
140
|
signup_account_rate_limiter?: RateLimiter | null;
|
|
118
|
-
/**
|
|
119
|
-
* Rate limiter for bearer token auth attempts (per-IP).
|
|
120
|
-
* Omit or `undefined` to use a default limiter (5 attempts per 15 minutes).
|
|
121
|
-
* Pass `null` to explicitly disable rate limiting.
|
|
122
|
-
*/
|
|
123
|
-
bearer_ip_rate_limiter?: RateLimiter | null;
|
|
124
141
|
/**
|
|
125
142
|
* Per-IP rate limiter for the action dispatchers (HTTP RPC + WebSocket).
|
|
126
143
|
* Consulted for actions whose spec declares `rate_limit: 'ip'` or `'both'`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEN,KAAK,cAAc,EAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAGN,KAAK,WAAW,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAKN,KAAK,WAAW,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAA4B,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEhF,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAGN,KAAK,eAAe,EACpB,MAAM,6BAA6B,CAAC;AASrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAKrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,sBAAsB,GACjC,wBAAwB,GAAG,2BAA2B,GAAG,oBAAoB,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,IAAI,EAAE,cAAc,CAAC;IACrB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAChC,2DAA2D;IAC3D,OAAO,EAAE,UAAU,CAAC;IACpB,6CAA6C;IAC7C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,sCAAsC;IACtC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAE/B,6BAA6B;IAC7B,KAAK,EAAE;QACN,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,iBAAiB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;KACtD,CAAC;IAEF
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -81,16 +81,23 @@ export const create_app_server = async (options) => {
|
|
|
81
81
|
const { deps } = backend;
|
|
82
82
|
const { log } = deps;
|
|
83
83
|
// Rate limiter defaults (undefined = default, null = disable)
|
|
84
|
-
|
|
84
|
+
// One instance per surface — see `AppServerOptions.login_ip_rate_limiter`
|
|
85
|
+
// for why these are not a single shared bucket.
|
|
86
|
+
const login_ip_rate_limiter = options.login_ip_rate_limiter === undefined
|
|
87
|
+
? create_rate_limiter()
|
|
88
|
+
: options.login_ip_rate_limiter;
|
|
89
|
+
const signup_ip_rate_limiter = options.signup_ip_rate_limiter === undefined
|
|
90
|
+
? create_rate_limiter()
|
|
91
|
+
: options.signup_ip_rate_limiter;
|
|
92
|
+
const bootstrap_ip_rate_limiter = options.bootstrap_ip_rate_limiter === undefined
|
|
93
|
+
? create_rate_limiter()
|
|
94
|
+
: options.bootstrap_ip_rate_limiter;
|
|
85
95
|
const login_account_rate_limiter = options.login_account_rate_limiter === undefined
|
|
86
96
|
? create_rate_limiter(default_login_account_rate_limit)
|
|
87
97
|
: options.login_account_rate_limiter;
|
|
88
98
|
const signup_account_rate_limiter = options.signup_account_rate_limiter === undefined
|
|
89
99
|
? create_rate_limiter(default_login_account_rate_limit)
|
|
90
100
|
: options.signup_account_rate_limiter;
|
|
91
|
-
const bearer_ip_rate_limiter = options.bearer_ip_rate_limiter === undefined
|
|
92
|
-
? create_rate_limiter()
|
|
93
|
-
: options.bearer_ip_rate_limiter;
|
|
94
101
|
const action_ip_rate_limiter = options.action_ip_rate_limiter === undefined
|
|
95
102
|
? create_rate_limiter(default_action_ip_rate_limit)
|
|
96
103
|
: options.action_ip_rate_limiter;
|
|
@@ -115,7 +122,6 @@ export const create_app_server = async (options) => {
|
|
|
115
122
|
const auth_middleware = await create_auth_middleware_specs(deps, {
|
|
116
123
|
allowed_origins: options.allowed_origins,
|
|
117
124
|
session_options: options.session_options,
|
|
118
|
-
bearer_ip_rate_limiter,
|
|
119
125
|
daemon_token_state: options.daemon_token_state
|
|
120
126
|
});
|
|
121
127
|
let middleware_specs = [proxy_spec, ...auth_middleware];
|
|
@@ -147,7 +153,9 @@ export const create_app_server = async (options) => {
|
|
|
147
153
|
backend,
|
|
148
154
|
bootstrap_status,
|
|
149
155
|
session_options: options.session_options,
|
|
150
|
-
|
|
156
|
+
login_ip_rate_limiter,
|
|
157
|
+
signup_ip_rate_limiter,
|
|
158
|
+
bootstrap_ip_rate_limiter,
|
|
151
159
|
login_account_rate_limiter,
|
|
152
160
|
signup_account_rate_limiter,
|
|
153
161
|
action_ip_rate_limiter,
|
|
@@ -166,7 +174,7 @@ export const create_app_server = async (options) => {
|
|
|
166
174
|
session_options: options.session_options,
|
|
167
175
|
bootstrap_status,
|
|
168
176
|
on_bootstrap: options.bootstrap.mode === 'live' ? options.bootstrap.on_bootstrap : undefined,
|
|
169
|
-
|
|
177
|
+
bootstrap_ip_rate_limiter
|
|
170
178
|
});
|
|
171
179
|
const prefix = options.bootstrap.route_prefix ?? '/api/account';
|
|
172
180
|
factory_routes.push(...prefix_route_specs(prefix, bootstrap_routes));
|
|
@@ -243,19 +251,21 @@ export const create_app_server = async (options) => {
|
|
|
243
251
|
});
|
|
244
252
|
}
|
|
245
253
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
254
|
+
// One diagnostic per surface — a deployment that disables login's limiter
|
|
255
|
+
// but keeps signup's is a different posture than one that disables both,
|
|
256
|
+
// and a single collapsed warning hid which surface was open.
|
|
257
|
+
for (const [name, limiter] of [
|
|
258
|
+
['login', login_ip_rate_limiter],
|
|
259
|
+
['signup', signup_ip_rate_limiter],
|
|
260
|
+
['bootstrap', bootstrap_ip_rate_limiter]
|
|
261
|
+
]) {
|
|
262
|
+
if (limiter === null) {
|
|
263
|
+
config_diagnostics.push({
|
|
264
|
+
level: 'warning',
|
|
265
|
+
category: 'config',
|
|
266
|
+
message: `${name} IP rate limiter explicitly disabled (null)`
|
|
267
|
+
});
|
|
268
|
+
}
|
|
259
269
|
}
|
|
260
270
|
if (config_diagnostics.length) {
|
|
261
271
|
surface_spec.surface.diagnostics = [...surface_spec.surface.diagnostics, ...config_diagnostics];
|
|
@@ -25,8 +25,16 @@ export interface AppServerContext {
|
|
|
25
25
|
backend: AppBackend;
|
|
26
26
|
bootstrap_status: BootstrapStatus;
|
|
27
27
|
session_options: SessionOptions<string>;
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Per-IP login + password-change rate limiter (from options). `null` when
|
|
30
|
+
* not configured. One instance per auth surface — see
|
|
31
|
+
* `AppServerOptions.login_ip_rate_limiter` for why these aren't shared.
|
|
32
|
+
*/
|
|
33
|
+
login_ip_rate_limiter: RateLimiter | null;
|
|
34
|
+
/** Per-IP signup rate limiter (from options). `null` when not configured. */
|
|
35
|
+
signup_ip_rate_limiter: RateLimiter | null;
|
|
36
|
+
/** Per-IP bootstrap rate limiter (from options). `null` when not configured. */
|
|
37
|
+
bootstrap_ip_rate_limiter: RateLimiter | null;
|
|
30
38
|
/** Per-account login rate limiter (from options). `null` when not configured. */
|
|
31
39
|
login_account_rate_limiter: RateLimiter | null;
|
|
32
40
|
/** Per-account signup rate limiter (from options). `null` when not configured. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,gBAAgB,EAAE,eAAe,CAAC;IAClC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,
|
|
1
|
+
{"version":3,"file":"app_server_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,gBAAgB,EAAE,eAAe,CAAC;IAClC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;OAIG;IACH,qBAAqB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1C,6EAA6E;IAC7E,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,gFAAgF;IAChF,yBAAyB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9C,iFAAiF;IACjF,0BAA0B,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,kFAAkF;IAClF,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,uGAAuG;IACvG,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,0GAA0G;IAC1G,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD;;;;OAIG;IACH,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9B"}
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -457,8 +457,8 @@ file that imports from `middleware.ts` gets these mocks globally. Pair with
|
|
|
457
457
|
- `BearerAuthTestOptions`, `BearerAuthTestCase` — test-case table shape for the bearer auth runner.
|
|
458
458
|
- `create_bearer_auth_mocks(tc)` — configures the module-level mocks per test case; returns spy references.
|
|
459
459
|
- `TEST_CLIENT_IP = '127.0.0.1'` — IP set by the proxy stub in `create_bearer_auth_test_app`.
|
|
460
|
-
- `create_bearer_auth_test_app(tc
|
|
461
|
-
- `describe_bearer_auth_cases(suite_name, cases
|
|
460
|
+
- `create_bearer_auth_test_app(tc)` — Hono app with bearer middleware + echo route at `/api/test` returning `{ok, account_id, credential_type, api_token_id, request_context_set}` — the account-grain identity bearer auth writes, plus a flag for tests that pre-populate `REQUEST_CONTEXT_KEY` via `pre_context`.
|
|
461
|
+
- `describe_bearer_auth_cases(suite_name, cases)` — table-driven runner; one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation.
|
|
462
462
|
- `TEST_MIDDLEWARE_PATH = '/api/test'` — path used by the echo route in the stack factory.
|
|
463
463
|
- `create_test_middleware_stack_app(options?)` — real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`.
|
|
464
464
|
|
|
@@ -571,17 +571,19 @@ Options: `{setup_test, surface_source, capabilities, sensitive_fields?, admin_on
|
|
|
571
571
|
|
|
572
572
|
### `rate_limiting.ts` — `describe_rate_limiting_tests`
|
|
573
573
|
|
|
574
|
-
|
|
574
|
+
Two test groups:
|
|
575
575
|
|
|
576
576
|
1. IP rate limiting on login — fires `max_attempts + 1` requests; last should be 429 with `RateLimitError` body + valid `Retry-After` header.
|
|
577
577
|
2. Per-account rate limiting on login — same username exhausts the bucket; a different username is not blocked.
|
|
578
|
-
|
|
578
|
+
|
|
579
|
+
No bearer group — the bearer path carries no rate limiter on either spine
|
|
580
|
+
(`auth/bearer_auth.ts`), which is also why `rpc_endpoints` is optional here.
|
|
579
581
|
|
|
580
582
|
Each group asserts its required route exists with a descriptive message.
|
|
581
583
|
Creates a tight rate limiter (default `max_attempts: 2`, `window_ms: 60_000`)
|
|
582
584
|
per test and disposes it in `finally`.
|
|
583
585
|
|
|
584
|
-
Options: `{session_options, create_route_specs, rpc_endpoints
|
|
586
|
+
Options: `{session_options, create_route_specs, rpc_endpoints?, app_options?, db_factories?, max_attempts?}`.
|
|
585
587
|
Reads inputs directly from the options bag instead of going through the
|
|
586
588
|
`setup_test` fixture protocol — the per-test rate-limiter overrides need a
|
|
587
589
|
fresh `TestApp` per test that the single-fixture model can't carry.
|
|
@@ -1395,6 +1397,27 @@ in-process `auth/origin_parity.db.test.ts` + the cross-process
|
|
|
1395
1397
|
Rust spine returned a plain-text body — now converged to the canonical TS
|
|
1396
1398
|
`{error: "forbidden_origin"}` via `fuz_http::forbidden_origin_response()`.
|
|
1397
1399
|
|
|
1400
|
+
### Query-string shape parity — `cross_backend/query_shape.ts`
|
|
1401
|
+
|
|
1402
|
+
`describe_query_shape_cross_tests({setup_test, capabilities, rpc_path?})` —
|
|
1403
|
+
the imperative duplicate-key / unknown-key / phase-order query-semantics
|
|
1404
|
+
suite over the three spine surfaces that read a query:
|
|
1405
|
+
`GET /api/account/status` (no query schema — duplicated `acting` first-wins,
|
|
1406
|
+
unknown keys ignored, anonymous junk query → 401 never a query 400), the
|
|
1407
|
+
JSON-RPC GET endpoint (`method` / `id` / `params` first-wins — a last-wins
|
|
1408
|
+
reader dispatches a different method per backend on the same request), and
|
|
1409
|
+
`GET /api/facts/:hash` (gated on `capabilities.fact_serving`; strict schema —
|
|
1410
|
+
unknown key / malformed `acting` → 400 `invalid_query_params` **before** the
|
|
1411
|
+
401 guard, duplicated `acting` first-wins). Imperative because duplicated
|
|
1412
|
+
query keys can't be expressed through the structured RPC helpers. Pinned
|
|
1413
|
+
after the Rust spine's derived-serde `Query` extractors were converged onto
|
|
1414
|
+
`fuz_http`'s `query_first` / `assert_known_query_keys` (a pre-handler
|
|
1415
|
+
"duplicate field" 400 is an anonymously observable backend fingerprint).
|
|
1416
|
+
Cross-process only — the per-surface in-process TS pins live beside each
|
|
1417
|
+
module's own tests (`account_status.test.ts`, `action_rpc.test.ts`,
|
|
1418
|
+
`serve_fact_route.db.test.ts`); fuz_app's own wiring is
|
|
1419
|
+
`cross_backend/query_shape.cross.test.ts`.
|
|
1420
|
+
|
|
1398
1421
|
### Readiness probe parity — `cross_backend/ready.ts`
|
|
1399
1422
|
|
|
1400
1423
|
`describe_ready_cross_tests({setup_test, capabilities, ready_path?})` — the
|
|
@@ -1495,7 +1518,7 @@ pay the 250ms denial floor.
|
|
|
1495
1518
|
|
|
1496
1519
|
`describe_login_security_cross_tests({setup_test, login_path?})` — the imperative
|
|
1497
1520
|
suite pinning **login rate limiting + `X-Forwarded-For` client-IP resolution**
|
|
1498
|
-
over real HTTP on both spines
|
|
1521
|
+
over real HTTP on both spines:
|
|
1499
1522
|
|
|
1500
1523
|
- **per-IP limit fires** — `default_login_ip_rate_limit.max_attempts` (5, the
|
|
1501
1524
|
shared cap on both impls) failed logins from one forwarded IP → 401, the next →
|
|
@@ -1505,15 +1528,26 @@ over real HTTP on both spines. Two cases:
|
|
|
1505
1528
|
- **XFF keying** — exhaust one forwarded IP to 429, then a _distinct_ forwarded IP
|
|
1506
1529
|
→ 401 (not 429), proving the limiter keys on the resolved `X-Forwarded-For` IP,
|
|
1507
1530
|
not the loopback TCP peer (a backend ignoring XFF would 429 the fresh IP too).
|
|
1531
|
+
- **a success does not refund the per-IP budget** — the distributed-spray
|
|
1532
|
+
backstop. Failed guesses against distinct usernames from one forwarded IP,
|
|
1533
|
+
interleaved with the attacker's own successful logins, must still 429 within a
|
|
1534
|
+
bounded total-request budget. Both spines used to clear the IP bucket on
|
|
1535
|
+
success; only the account-grain bucket is forgiven now. The **budget bound** is
|
|
1536
|
+
what makes this adversarial — a decrement-instead-of-zero implementation loops
|
|
1537
|
+
to the iteration cap and fails here. Either leg may trip: the aggregate governs
|
|
1538
|
+
the address, so once it fills the attacker's own login is refused too.
|
|
1508
1539
|
|
|
1509
1540
|
**Cross-process only**, on a **dedicated dual-spawn project** (`cross_backend_security`
|
|
1510
1541
|
via `global_setup_login_security.ts`) — the limiters can't be enabled on a backend
|
|
1511
1542
|
the standard suites share (they fire many loopback logins a live limiter would
|
|
1512
1543
|
429), so the standard backends keep every limiter null. Determinism without a
|
|
1513
1544
|
limiter reset: each case uses its own forwarded IP (a fresh bucket) plus its own
|
|
1514
|
-
non-existent username
|
|
1545
|
+
non-existent username; the spray case additionally mints its attacker account
|
|
1546
|
+
over the setup path (loopback, no XFF), so minting can't touch the bucket under
|
|
1547
|
+
test. Zero Rust code change — the stub's `FUZ_LOGIN_RATE_LIMIT_ENABLED`
|
|
1515
1548
|
and `FUZ_TRUSTED_PROXIES` env-gates were already wired; the TS side env-gates the
|
|
1516
|
-
limiters in the binary, and `create_spine_route_specs` honors
|
|
1549
|
+
limiters in the binary, and `create_spine_route_specs` honors
|
|
1550
|
+
`ctx.login_ip_rate_limiter`.
|
|
1517
1551
|
The in-process counterparts already exist (`describe_rate_limiting_tests` plus the
|
|
1518
1552
|
proxy middleware tests), so there's no in-process leg. `npm run test:cross:security`.
|
|
1519
1553
|
Cited property: `docs/security.md` §"Rate Limiting" + §"Trusted Proxy / Client IP".
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -276,10 +276,11 @@ export const create_test_app = async (options) => {
|
|
|
276
276
|
allowed_origins: [/^http:\/\/localhost/],
|
|
277
277
|
proxy: { trusted_proxies: ['127.0.0.1'], get_connection_ip: () => '127.0.0.1' },
|
|
278
278
|
env_schema: z.object({}),
|
|
279
|
-
|
|
279
|
+
login_ip_rate_limiter: null,
|
|
280
|
+
signup_ip_rate_limiter: null,
|
|
281
|
+
bootstrap_ip_rate_limiter: null,
|
|
280
282
|
login_account_rate_limiter: null,
|
|
281
283
|
signup_account_rate_limiter: null,
|
|
282
|
-
bearer_ip_rate_limiter: null,
|
|
283
284
|
await_pending_effects: true,
|
|
284
285
|
daemon_token_state,
|
|
285
286
|
rpc_endpoints: options.rpc_endpoints,
|
|
@@ -402,10 +403,11 @@ export const create_test_app_for_bootstrap = async (options) => {
|
|
|
402
403
|
allowed_origins: [/^http:\/\/localhost/],
|
|
403
404
|
proxy: { trusted_proxies: ['127.0.0.1'], get_connection_ip: () => '127.0.0.1' },
|
|
404
405
|
env_schema: z.object({}),
|
|
405
|
-
|
|
406
|
+
login_ip_rate_limiter: null,
|
|
407
|
+
signup_ip_rate_limiter: null,
|
|
408
|
+
bootstrap_ip_rate_limiter: null,
|
|
406
409
|
login_account_rate_limiter: null,
|
|
407
410
|
signup_account_rate_limiter: null,
|
|
408
|
-
bearer_ip_rate_limiter: null,
|
|
409
411
|
await_pending_effects: true,
|
|
410
412
|
daemon_token_state,
|
|
411
413
|
rpc_endpoints: options.rpc_endpoints,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAUhE,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AA2B1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,0BAA0B,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AAgGD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,
|
|
1
|
+
{"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAUhE,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AA2B1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,0BAA0B,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AAgGD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IA6mBzF,CAAC"}
|
|
@@ -561,7 +561,11 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
561
561
|
'role_grant_offer_decline',
|
|
562
562
|
'role_grant_offer_retract',
|
|
563
563
|
'role_grant_offer_expire',
|
|
564
|
-
'role_grant_offer_supersede'
|
|
564
|
+
'role_grant_offer_supersede',
|
|
565
|
+
// `db_admin_row_delete` fires from the generic db-admin browser
|
|
566
|
+
// (`http/db_routes.ts`), which the standard test app doesn't mount —
|
|
567
|
+
// covered in `db_routes.db.test.ts`.
|
|
568
|
+
'db_admin_row_delete'
|
|
565
569
|
]);
|
|
566
570
|
test('all audit event types are covered or explicitly excluded', () => {
|
|
567
571
|
const all_covered = new Set([...COVERED_EVENT_TYPES, ...EXCLUDED_EVENT_TYPES]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_relations.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_relations.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cell_relations.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_relations.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4F9B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAsF3D,eAAO,MAAM,mCAAmC,GAAI,SAAS,wBAAwB,KAAG,IAi2BvF,CAAC"}
|
|
@@ -27,6 +27,12 @@ import '../assert_dev_env.js';
|
|
|
27
27
|
* - **clone** — shallow copies item / field *edges* (shared `child_id` /
|
|
28
28
|
* `target_id`); deep clones each viewable child into a fresh cell at the
|
|
29
29
|
* same position. Both null `path` and stamp the caller as owner.
|
|
30
|
+
* - **`shared_with: 'me'`** — the grant-driven `cell_list` branch: a grantee
|
|
31
|
+
* lists exactly the cells that admit them via `cell_grant`, their own cells
|
|
32
|
+
* excluded, with the `cell_grants` enrichment keyed by cell id. Plus the two
|
|
33
|
+
* guards — null-auth is `cell_list_shared_with_requires_auth`, and any value
|
|
34
|
+
* other than `'me'` is `invalid_params` on both spines. The cross twin of
|
|
35
|
+
* the in-process `auth/cell_actions.list.db.test.ts` §"shared_with: me".
|
|
30
36
|
* - **audit** — `cell_audit_list` is manage-tier: the owner reads the cell's
|
|
31
37
|
* timeline; a viewer-grant holder who can `cell_get` the cell still gets the
|
|
32
38
|
* IDOR 404 on the timeline (D14).
|
|
@@ -53,7 +59,7 @@ import '../assert_dev_env.js';
|
|
|
53
59
|
*/
|
|
54
60
|
import { describe, assert } from 'vitest';
|
|
55
61
|
import { fractional_index_between } from '@fuzdev/fuz_util/fractional_index.ts';
|
|
56
|
-
import { CellCreateOutput, CellUpdateOutput, CellCloneOutput, CellGetOutput } from '../../auth/cell_action_specs.js';
|
|
62
|
+
import { CellCreateOutput, CellUpdateOutput, CellCloneOutput, CellGetOutput, CellListOutput } from '../../auth/cell_action_specs.js';
|
|
57
63
|
import { AuditLogListOutput } from '../../auth/admin_action_specs.js';
|
|
58
64
|
import { CellGrantCreateOutput, CellGrantListOutput, CellGrantRevokeOutput } from '../../auth/cell_grant_action_specs.js';
|
|
59
65
|
import { CellFieldDeleteOutput, CellFieldListOutput, CellFieldSetOutput } from '../../auth/cell_field_action_specs.js';
|
|
@@ -131,6 +137,52 @@ export const describe_cell_relations_cross_tests = (options) => {
|
|
|
131
137
|
assert.ok(!post.ok, 'revoked editor still edited');
|
|
132
138
|
assert.strictEqual(error_reason(post), 'cell_not_found');
|
|
133
139
|
});
|
|
140
|
+
test_if(capabilities.cell_relations, "cell_list shared_with: 'me' lists grant-admitted cells, excludes owned, enriches cell_grants", async () => {
|
|
141
|
+
const fixture = await setup_test();
|
|
142
|
+
const owner = await fixture.create_account({ username: 'cell_shared_owner' });
|
|
143
|
+
const viewer = await fixture.create_account({ username: 'cell_shared_viewer' });
|
|
144
|
+
const t = fixture.fresh_transport();
|
|
145
|
+
const owner_h = owner.create_session_headers();
|
|
146
|
+
const viewer_h = viewer.create_session_headers();
|
|
147
|
+
const shared = await create_cell(t, rpc_path, owner_h, { kind: 'note', data: {} });
|
|
148
|
+
// A cell the viewer owns — owner ≠ sharee, so it must NOT appear.
|
|
149
|
+
await create_cell(t, rpc_path, viewer_h, { kind: 'note', data: {} });
|
|
150
|
+
// The grant-admit control: owner-owned but NOT granted to the viewer.
|
|
151
|
+
// Without it the semi-join is untested — the shared-with SQL's two
|
|
152
|
+
// conjuncts (created_by IS DISTINCT FROM caller AND id IN grant-set)
|
|
153
|
+
// would select the same set, so dropping the grant clause changes
|
|
154
|
+
// nothing. This ungranted cell is exactly what dropping it would leak.
|
|
155
|
+
await create_cell(t, rpc_path, owner_h, { kind: 'note', data: {} });
|
|
156
|
+
const grant = expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_create', {
|
|
157
|
+
cell_id: shared,
|
|
158
|
+
level: 'viewer',
|
|
159
|
+
principal: { kind: 'actor', actor_id: viewer.actor.id }
|
|
160
|
+
}, owner_h), CellGrantCreateOutput).grant;
|
|
161
|
+
const listed = expect_output(await cross_rpc_call(t, rpc_path, 'cell_list', { shared_with: 'me' }, viewer_h), CellListOutput);
|
|
162
|
+
assert.deepStrictEqual(listed.cells.map((c) => c.id), [shared], 'shared_with list is not exactly the grant-admitted cell');
|
|
163
|
+
// The enrichment: the caller's own admit grants, keyed by cell id.
|
|
164
|
+
assert.ok(listed.cell_grants, 'shared_with list omitted the cell_grants enrichment');
|
|
165
|
+
const grants = listed.cell_grants[shared];
|
|
166
|
+
assert.ok(grants, 'cell_grants missing the shared cell key');
|
|
167
|
+
assert.strictEqual(grants.length, 1);
|
|
168
|
+
assert.strictEqual(grants[0].id, grant.id);
|
|
169
|
+
});
|
|
170
|
+
test_if(capabilities.cell_relations, 'null-auth cell_list shared_with → cell_list_shared_with_requires_auth', async () => {
|
|
171
|
+
const fixture = await setup_test();
|
|
172
|
+
const anon = fixture.fresh_transport({ origin: null });
|
|
173
|
+
const bad = await cross_rpc_call(anon, rpc_path, 'cell_list', { shared_with: 'me' }, {});
|
|
174
|
+
assert.ok(!bad.ok, 'anon shared_with filter accepted');
|
|
175
|
+
assert.strictEqual(error_reason(bad), 'cell_list_shared_with_requires_auth');
|
|
176
|
+
});
|
|
177
|
+
test_if(capabilities.cell_relations, "cell_list shared_with other than 'me' → invalid_params", async () => {
|
|
178
|
+
const fixture = await setup_test();
|
|
179
|
+
// TS rejects at the schema (`z.literal('me')`), Rust in the handler
|
|
180
|
+
// guard — both must land on -32602, so a caller can't widen the
|
|
181
|
+
// grant-driven branch to another actor on either spine.
|
|
182
|
+
const bad = await cross_rpc_call(fixture.fresh_transport(), rpc_path, 'cell_list', { shared_with: 'not-me' }, fixture.create_session_headers());
|
|
183
|
+
assert.ok(!bad.ok, "cell_list accepted a shared_with other than 'me'");
|
|
184
|
+
assert.strictEqual(bad.error?.code, -32602);
|
|
185
|
+
});
|
|
134
186
|
test_if(capabilities.cell_relations, 'editor-grant holder cannot flip visibility → cell_visibility_manage_only', async () => {
|
|
135
187
|
const fixture = await setup_test();
|
|
136
188
|
const owner = await fixture.create_account({ username: 'cell_vis_owner' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_spine_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_spine_surface.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAItD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI1F,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAe3E;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,MAAM,CAAwC,CAAC;AAElG;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,EAAE,gBAGxB,CAAC;AAEH,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACzD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAC/B,KAAK,gBAAgB,EACrB,UAAU,wBAAwB,KAChC,KAAK,CAAC,eAAe,CAQvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,KAAK,gBAAgB,KAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"default_spine_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_spine_surface.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAItD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI1F,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAe3E;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,MAAM,CAAwC,CAAC;AAElG;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,EAAE,gBAGxB,CAAC;AAEH,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACzD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAC/B,KAAK,gBAAgB,EACrB,UAAU,wBAAwB,KAChC,KAAK,CAAC,eAAe,CAQvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,KAAK,gBAAgB,KAAG,KAAK,CAAC,SAAS,CAgC/E,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,6BAA6B,GAAI,MAAM,MAAM,KAAG,SAC+B,CAAC;AAE7F;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,QAAO,cAM1C,CAAC"}
|
|
@@ -72,20 +72,21 @@ export const create_spine_route_specs = (ctx) => [
|
|
|
72
72
|
...create_account_route_specs(ctx.deps, {
|
|
73
73
|
session_options: spine_session_options,
|
|
74
74
|
// Honor the limiters the server was assembled with (on `AppServerContext`
|
|
75
|
-
// per the `
|
|
76
|
-
// than hardcoding `null`. The standard spine binary passes `null`
|
|
77
|
-
// cross suites fire many loopback logins and must not trip a
|
|
78
|
-
// this is behavior-preserving there; the dedicated
|
|
79
|
-
// backend passes real limiters to exercise the 429 +
|
|
80
|
-
// and XFF-keyed bucketing over the wire (see
|
|
81
|
-
|
|
75
|
+
// per the `login_ip_rate_limiter` / `login_account_rate_limiter` TSDoc)
|
|
76
|
+
// rather than hardcoding `null`. The standard spine binary passes `null`
|
|
77
|
+
// (the cross suites fire many loopback logins and must not trip a
|
|
78
|
+
// limiter), so this is behavior-preserving there; the dedicated
|
|
79
|
+
// login-security cross backend passes real limiters to exercise the 429 +
|
|
80
|
+
// `Retry-After` path and XFF-keyed bucketing over the wire (see
|
|
81
|
+
// `login_security.ts`).
|
|
82
|
+
login_ip_rate_limiter: ctx.login_ip_rate_limiter,
|
|
82
83
|
login_account_rate_limiter: ctx.login_account_rate_limiter,
|
|
83
84
|
login_fail_floor_ms: 0,
|
|
84
85
|
bootstrap_status: ctx.bootstrap_status
|
|
85
86
|
}),
|
|
86
87
|
...create_signup_route_specs(ctx.deps, {
|
|
87
88
|
session_options: spine_session_options,
|
|
88
|
-
|
|
89
|
+
signup_ip_rate_limiter: null,
|
|
89
90
|
signup_account_rate_limiter: null,
|
|
90
91
|
// Disable the denial floor so the identity-parity suite's accepted
|
|
91
92
|
// cases (valid username/email, no invite → 403 no-matching-invite)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login_security.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/login_security.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"login_security.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/login_security.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8D9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,mDAAmD;AACnD,MAAM,WAAW,6BAA6B;IAC7C,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,kFAAkF;IAClF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AA0BD,eAAO,MAAM,mCAAmC,GAC/C,SAAS,6BAA6B,KACpC,IA2KF,CAAC"}
|