@fuzdev/fuz_app 0.140.0 → 0.142.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/dist/actions/CLAUDE.md +72 -22
- package/dist/actions/action_rpc.d.ts +5 -1
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +9 -1
- package/dist/actions/connection_closer.d.ts +44 -4
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +33 -3
- package/dist/actions/perform_action.d.ts +10 -0
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +23 -9
- package/dist/actions/register_action_ws.d.ts +42 -6
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +87 -19
- package/dist/actions/register_ws_endpoint.d.ts +15 -6
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +10 -4
- package/dist/actions/socket.svelte.d.ts +19 -4
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +31 -4
- package/dist/actions/transports.d.ts +30 -1
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -1
- package/dist/actions/transports_ws_auth_guard.d.ts +13 -6
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +24 -10
- package/dist/actions/transports_ws_backend.d.ts +51 -5
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +62 -9
- package/dist/actions/ws_endpoint_spec.d.ts +11 -10
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +44 -22
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +12 -1
- package/dist/auth/account_route_schema.d.ts +1 -0
- package/dist/auth/account_route_schema.d.ts.map +1 -1
- package/dist/auth/account_route_schema.js +12 -0
- package/dist/auth/account_routes.d.ts +7 -2
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +240 -187
- package/dist/auth/admin_action_specs.d.ts +6 -1
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +6 -1
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +14 -2
- package/dist/auth/api_token.d.ts +20 -0
- package/dist/auth/api_token.d.ts.map +1 -1
- package/dist/auth/api_token.js +21 -1
- package/dist/auth/api_token_queries.d.ts +22 -4
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +11 -6
- package/dist/auth/audit_log_routes.d.ts +10 -0
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +20 -0
- package/dist/auth/audit_log_schema.d.ts +30 -5
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +30 -0
- package/dist/auth/bearer_auth.d.ts +4 -2
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +19 -8
- package/dist/auth/bootstrap_route_schema.d.ts +1 -0
- package/dist/auth/bootstrap_route_schema.d.ts.map +1 -1
- package/dist/auth/bootstrap_route_schema.js +1 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +85 -76
- package/dist/auth/cell_action_specs.d.ts +7 -3
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +9 -5
- package/dist/auth/cell_actions.d.ts +3 -3
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +67 -38
- package/dist/auth/cell_authorize.d.ts +69 -8
- package/dist/auth/cell_authorize.d.ts.map +1 -1
- package/dist/auth/cell_authorize.js +89 -9
- package/dist/auth/cell_field_action_specs.d.ts +5 -4
- package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_field_action_specs.js +7 -7
- package/dist/auth/cell_field_actions.d.ts +7 -5
- package/dist/auth/cell_field_actions.d.ts.map +1 -1
- package/dist/auth/cell_field_actions.js +24 -22
- package/dist/auth/cell_grant_action_specs.d.ts +6 -0
- package/dist/auth/cell_grant_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_grant_action_specs.js +6 -0
- package/dist/auth/cell_grant_actions.d.ts +3 -1
- package/dist/auth/cell_grant_actions.d.ts.map +1 -1
- package/dist/auth/cell_grant_actions.js +16 -2
- package/dist/auth/cell_item_action_specs.d.ts +5 -4
- package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_item_action_specs.js +7 -7
- package/dist/auth/cell_item_actions.d.ts +6 -5
- package/dist/auth/cell_item_actions.d.ts.map +1 -1
- package/dist/auth/cell_item_actions.js +23 -22
- package/dist/auth/cell_relation_list_limit.d.ts +20 -0
- package/dist/auth/cell_relation_list_limit.d.ts.map +1 -0
- package/dist/auth/cell_relation_list_limit.js +27 -0
- package/dist/auth/cell_relation_visibility.d.ts +4 -3
- package/dist/auth/cell_relation_visibility.d.ts.map +1 -1
- package/dist/auth/cell_relation_visibility.js +6 -5
- package/dist/auth/cell_steward.d.ts +45 -0
- package/dist/auth/cell_steward.d.ts.map +1 -0
- package/dist/auth/cell_steward.js +53 -0
- package/dist/auth/cleanup.d.ts +9 -9
- package/dist/auth/cleanup.js +9 -9
- package/dist/auth/credential_deadline.d.ts +95 -0
- package/dist/auth/credential_deadline.d.ts.map +1 -0
- package/dist/auth/credential_deadline.js +139 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +4 -1
- package/dist/auth/middleware.d.ts +90 -12
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +115 -16
- package/dist/auth/request_context.d.ts +8 -2
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +20 -4
- package/dist/auth/resolved_auth.d.ts +13 -2
- package/dist/auth/resolved_auth.d.ts.map +1 -1
- package/dist/auth/resolved_auth.js +5 -4
- package/dist/auth/role_grant_offer_action_specs.d.ts +5 -0
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +6 -1
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +23 -16
- package/dist/auth/role_grant_offer_queries.d.ts +8 -6
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +16 -8
- package/dist/auth/session_cookie.d.ts +4 -0
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +3 -2
- package/dist/auth/session_middleware.d.ts +1 -1
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +4 -1
- package/dist/auth/session_queries.d.ts +19 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +8 -2
- package/dist/auth/signup_route_schema.d.ts.map +1 -1
- package/dist/auth/signup_route_schema.js +1 -0
- package/dist/auth/signup_routes.d.ts +4 -3
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +157 -134
- package/dist/auth/token_scope.d.ts +7 -1
- package/dist/auth/token_scope.d.ts.map +1 -1
- package/dist/auth/token_scope.js +8 -2
- package/dist/db/CLAUDE.md +32 -19
- package/dist/db/cell_ddl.d.ts +1 -2
- package/dist/db/cell_ddl.d.ts.map +1 -1
- package/dist/db/cell_ddl.js +1 -2
- package/dist/db/cell_field_queries.d.ts +20 -18
- package/dist/db/cell_field_queries.d.ts.map +1 -1
- package/dist/db/cell_field_queries.js +28 -22
- package/dist/db/cell_item_queries.d.ts +20 -14
- package/dist/db/cell_item_queries.d.ts.map +1 -1
- package/dist/db/cell_item_queries.js +28 -18
- package/dist/db/cell_moderation.d.ts +67 -0
- package/dist/db/cell_moderation.d.ts.map +1 -0
- package/dist/db/cell_moderation.js +66 -0
- package/dist/db/cell_queries.d.ts +44 -14
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +68 -45
- package/dist/db/cell_view_sql.d.ts +102 -0
- package/dist/db/cell_view_sql.d.ts.map +1 -0
- package/dist/db/cell_view_sql.js +112 -0
- package/dist/db/db_pg.d.ts +1 -1
- package/dist/db/db_pg.js +1 -1
- package/dist/hono_context.d.ts +23 -0
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +19 -0
- package/dist/http/CLAUDE.md +41 -15
- package/dist/http/auth_shape.d.ts +5 -2
- package/dist/http/auth_shape.d.ts.map +1 -1
- package/dist/http/auth_shape.js +5 -2
- package/dist/http/ip_canonical.d.ts +30 -3
- package/dist/http/ip_canonical.d.ts.map +1 -1
- package/dist/http/ip_canonical.js +50 -3
- package/dist/http/middleware_spec.d.ts +16 -0
- package/dist/http/middleware_spec.d.ts.map +1 -1
- package/dist/http/origin.d.ts +113 -18
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +247 -127
- package/dist/http/route_spec.d.ts +21 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/schema_helpers.d.ts +22 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +24 -0
- package/dist/http/surface.d.ts +6 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +12 -5
- package/dist/primitive_schemas.d.ts +10 -1
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +11 -2
- package/dist/rate_limiter.d.ts +179 -12
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +352 -42
- package/dist/realtime/sse_auth_guard.d.ts +22 -6
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +31 -12
- package/dist/realtime/subscriber_registry.d.ts +10 -1
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +10 -1
- package/dist/server/app_server.d.ts +20 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +8 -3
- package/dist/server/env.d.ts +2 -1
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +7 -17
- package/dist/server/serve_fact_route.d.ts +8 -4
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +16 -6
- package/dist/testing/CLAUDE.md +164 -25
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +13 -6
- package/dist/testing/connection_closer_helpers.d.ts +6 -1
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +4 -0
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +37 -2
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +14 -65
- package/dist/testing/cross_backend/capabilities.d.ts +26 -2
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +9 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts +38 -0
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +401 -5
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.js +145 -2
- package/dist/testing/cross_backend/conformance_case.d.ts +11 -3
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_case.js +6 -0
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +20 -19
- package/dist/testing/cross_backend/credential_deadline.d.ts +25 -0
- package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -0
- package/dist/testing/cross_backend/credential_deadline.js +185 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +13 -2
- package/dist/testing/cross_backend/expected_schema.json +0 -1
- package/dist/testing/cross_backend/full_spine_mount.d.ts +3 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +7 -1
- package/dist/testing/cross_backend/login_security.d.ts +16 -0
- package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
- package/dist/testing/cross_backend/login_security.js +154 -0
- package/dist/testing/cross_backend/narrowed_api_token.d.ts +23 -0
- package/dist/testing/cross_backend/narrowed_api_token.d.ts.map +1 -0
- package/dist/testing/cross_backend/narrowed_api_token.js +40 -0
- package/dist/testing/cross_backend/origin.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin.js +6 -26
- package/dist/testing/cross_backend/origin_conformance.d.ts +152 -0
- package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_conformance.js +136 -0
- package/dist/testing/cross_backend/origin_conformance.json +1679 -0
- package/dist/testing/cross_backend/origin_scope.d.ts +16 -0
- package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_scope.js +140 -0
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
- package/dist/testing/cross_backend/query_shape.js +24 -2
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +35 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.js +64 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +8 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +44 -33
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +64 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +6 -4
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +20 -1
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +23 -1
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +20 -7
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +180 -5
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +154 -5
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_scope_surface.js +25 -21
- package/dist/testing/cross_backend/transport_composition.d.ts +60 -0
- package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -0
- package/dist/testing/cross_backend/transport_composition.js +364 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +21 -6
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_action_rate_limit.js +21 -1
- package/dist/testing/cross_backend/ws_role_gated.d.ts +38 -0
- package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_role_gated.js +142 -0
- package/dist/testing/entities.d.ts +23 -0
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +37 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +3 -1
- package/dist/testing/middleware.d.ts +10 -0
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +31 -7
- package/dist/testing/schema_introspect.js +1 -1
- package/dist/testing/schema_parity.d.ts +4 -3
- package/dist/testing/schema_parity.d.ts.map +1 -1
- package/dist/testing/schema_parity.js +4 -3
- package/dist/testing/schema_ready_fixture.d.ts +2 -4
- package/dist/testing/schema_ready_fixture.d.ts.map +1 -1
- package/dist/testing/schema_ready_fixture.js +2 -4
- package/dist/testing/stubs.d.ts +16 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +20 -7
- package/dist/testing/surface_invariants.js +2 -2
- package/dist/ui/auth_state.svelte.d.ts +10 -0
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +22 -4
- package/package.json +1 -1
- package/dist/db/cell_history_ddl.d.ts +0 -38
- package/dist/db/cell_history_ddl.d.ts.map +0 -1
- package/dist/db/cell_history_ddl.js +0 -61
package/dist/http/origin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Request source verification middleware for API protection.
|
|
3
3
|
*
|
|
4
|
-
* Verifies requests
|
|
4
|
+
* Verifies requests carry an `Origin` the server allows, or none.
|
|
5
5
|
* CSRF protection is `SameSite: strict` on session cookies
|
|
6
6
|
* (see `auth/session_middleware.ts`) plus the CORS simple-request refusal
|
|
7
7
|
* (`http/simple_request.ts`) — `SameSite` alone admits same-site pages, which
|
|
@@ -10,10 +10,18 @@
|
|
|
10
10
|
* from making requests as the user browses the web — and is the only gate on
|
|
11
11
|
* the WebSocket upgrade, which is never preflighted.
|
|
12
12
|
*
|
|
13
|
+
* The allowlist grammar is shared with the Rust spine entry for entry:
|
|
14
|
+
* `parse_allowed_origins` accepts and refuses the same entries, naming each
|
|
15
|
+
* refusal with the same `AllowedOriginsErrorKind` string, and an accepted list
|
|
16
|
+
* matches the same origins. The shared conformance table
|
|
17
|
+
* (`testing/cross_backend/origin_conformance.json`) pins both.
|
|
18
|
+
*
|
|
13
19
|
* @module
|
|
14
20
|
*/
|
|
15
21
|
import { escape_regexp } from '@fuzdev/fuz_util/regexp.ts';
|
|
22
|
+
import { z } from 'zod';
|
|
16
23
|
import { ERROR_FORBIDDEN_ORIGIN } from './error_schemas.js';
|
|
24
|
+
import { middleware_applies } from './schema_helpers.js';
|
|
17
25
|
/**
|
|
18
26
|
* True when the request looks like it originated from a browser context — it
|
|
19
27
|
* carries an `Origin` or `Referer` header. Browsers attach these
|
|
@@ -32,37 +40,134 @@ import { ERROR_FORBIDDEN_ORIGIN } from './error_schemas.js';
|
|
|
32
40
|
*/
|
|
33
41
|
export const is_browser_context = (c) => c.req.header('Origin') !== undefined || c.req.header('Referer') !== undefined;
|
|
34
42
|
/**
|
|
35
|
-
*
|
|
43
|
+
* Why one allowlist entry was refused. The wire names both spines emit — the
|
|
44
|
+
* Rust spine's `OriginPatternError::kind` returns the same strings.
|
|
45
|
+
*/
|
|
46
|
+
export const OriginPatternErrorKind = z.enum([
|
|
47
|
+
'empty_entry',
|
|
48
|
+
'not_printable_ascii',
|
|
49
|
+
'missing_scheme',
|
|
50
|
+
'unsupported_scheme',
|
|
51
|
+
'has_path',
|
|
52
|
+
'has_userinfo',
|
|
53
|
+
'missing_host',
|
|
54
|
+
'invalid_host_char',
|
|
55
|
+
'unbracketed_ipv6',
|
|
56
|
+
'partial_wildcard',
|
|
57
|
+
'non_canonical_ipv4',
|
|
58
|
+
'unclosed_ipv6',
|
|
59
|
+
'invalid_ipv6',
|
|
60
|
+
'invalid_after_ipv6',
|
|
61
|
+
'invalid_port',
|
|
62
|
+
'default_port'
|
|
63
|
+
]);
|
|
64
|
+
/** Why an allowlist value was refused: `no_origins` (a blank value) or an entry's kind. */
|
|
65
|
+
export const AllowedOriginsErrorKind = z.enum(['no_origins', ...OriginPatternErrorKind.options]);
|
|
66
|
+
/** The operator-facing reason for each refusal kind. */
|
|
67
|
+
export const ALLOWED_ORIGINS_ERROR_MESSAGES = {
|
|
68
|
+
no_origins: 'no origins supplied — list at least one',
|
|
69
|
+
empty_entry: 'it is empty (a stray comma?)',
|
|
70
|
+
not_printable_ascii: 'an origin is printable ASCII with no spaces (an international hostname is written in its punycode form)',
|
|
71
|
+
missing_scheme: 'it has no `scheme://`',
|
|
72
|
+
unsupported_scheme: 'the scheme is neither http nor https',
|
|
73
|
+
has_path: 'an origin ends at the host or port — no path, query, or fragment, and no trailing slash',
|
|
74
|
+
has_userinfo: 'an origin carries no userinfo',
|
|
75
|
+
missing_host: 'it has no host',
|
|
76
|
+
invalid_host_char: 'a hostname holds none of `%`, `\\`, `^`, `|`, `<`, `>`, `[`, `]` (a browser sends it decoded, with no percent-encoding)',
|
|
77
|
+
unbracketed_ipv6: 'an IPv6 address is written in brackets, `[::1]`',
|
|
78
|
+
partial_wildcard: 'a `*` stands for one whole host label, as in `https://*.example.com`',
|
|
79
|
+
non_canonical_ipv4: 'a host ending in a number is an IPv4 address, which a browser sends as four decimal numbers 0-255 with no leading zeros and no trailing dot',
|
|
80
|
+
unclosed_ipv6: 'the IPv6 address has no closing `]`',
|
|
81
|
+
invalid_ipv6: 'the bracketed host is not an IPv6 address written the way a browser sends it: hex groups without leading zeros, the longest run of zero groups as `::`, no dotted-quad tail, no zone',
|
|
82
|
+
invalid_after_ipv6: 'only `:port` may follow the IPv6 address',
|
|
83
|
+
invalid_port: 'the port is neither a number in 1-65535 (no leading zeros) nor `*`',
|
|
84
|
+
default_port: "it names the scheme's default port, which a browser leaves out of `Origin` and `Host` — write it without the port"
|
|
85
|
+
};
|
|
86
|
+
/** The longest excerpt of a refused entry an error message quotes. */
|
|
87
|
+
const ENTRY_EXCERPT_MAX = 200;
|
|
88
|
+
/**
|
|
89
|
+
* Render one refusal for a boot error — the entry in double quotes with every
|
|
90
|
+
* character but visible ASCII and the space escaped as `\uXXXX` (and `"` and
|
|
91
|
+
* `\` backslash-escaped), so an env value can't put a control, bidi, or other
|
|
92
|
+
* non-printing character in a log, nor close the quotes it is shown in.
|
|
93
|
+
*
|
|
94
|
+
* @param error - one of `parse_allowed_origins`'s errors
|
|
95
|
+
* @returns the reason as one line
|
|
96
|
+
*/
|
|
97
|
+
export const format_allowed_origins_error = (error) => {
|
|
98
|
+
const reason = ALLOWED_ORIGINS_ERROR_MESSAGES[error.kind];
|
|
99
|
+
if (error.index === undefined)
|
|
100
|
+
return reason;
|
|
101
|
+
const entry = error.entry ?? '';
|
|
102
|
+
const excerpt = entry.length > ENTRY_EXCERPT_MAX ? entry.slice(0, ENTRY_EXCERPT_MAX) + '...' : entry;
|
|
103
|
+
return `entry ${error.index} ${quote_ascii(excerpt)} is refused: ${reason}`;
|
|
104
|
+
};
|
|
105
|
+
/** Everything outside visible ASCII and the space, plus the quote and backslash. */
|
|
106
|
+
const NEEDS_ASCII_ESCAPE = /[^\x20-\x7e]|["\\]/g;
|
|
107
|
+
/**
|
|
108
|
+
* `value` in double quotes, ASCII-only: `"` and `\` backslash-escaped, every
|
|
109
|
+
* other UTF-16 code unit outside `\x20-\x7e` as `\uXXXX`.
|
|
110
|
+
*/
|
|
111
|
+
const quote_ascii = (value) => '"' +
|
|
112
|
+
value.replace(NEEDS_ASCII_ESCAPE, (c) => c === '"' || c === '\\' ? '\\' + c : '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0')) +
|
|
113
|
+
'"';
|
|
114
|
+
/** Printable ASCII without the space. */
|
|
115
|
+
const VISIBLE_ASCII = /^[\x21-\x7e]*$/;
|
|
116
|
+
/** The ASCII whitespace an entry is trimmed of — space, tab, LF, FF, CR. */
|
|
117
|
+
const ASCII_WHITESPACE_EDGES = /^[ \t\n\f\r]+|[ \t\n\f\r]+$/g;
|
|
118
|
+
const trim_ascii_whitespace = (value) => value.replace(ASCII_WHITESPACE_EDGES, '');
|
|
119
|
+
/**
|
|
120
|
+
* Parses an allowlist value (conventionally the `FUZ_ALLOWED_ORIGINS` env var)
|
|
121
|
+
* into regex matchers for request source verification.
|
|
36
122
|
* Origin allowlisting for locally-running services — not the CSRF layer
|
|
37
123
|
* (that's `SameSite: strict` on session cookies plus `http/simple_request.ts`).
|
|
38
124
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* -
|
|
43
|
-
* - Wildcard
|
|
44
|
-
*
|
|
125
|
+
* Entries are comma-separated and trimmed of ASCII whitespace. Each is written
|
|
126
|
+
* the way a browser writes an `Origin` — `scheme://host[:port]` — where a whole
|
|
127
|
+
* host label or the port may be `*`:
|
|
128
|
+
* - Exact origins: `https://api.fuz.dev`, `http://localhost:3000`
|
|
129
|
+
* - Wildcard labels: `https://*.fuz.dev` (each `*` is exactly one label, in any
|
|
130
|
+
* position — `api.fuz.dev` matches, `fuz.dev` and `a.b.fuz.dev` don't)
|
|
131
|
+
* - Wildcard ports: `http://localhost:*` (any port or none)
|
|
132
|
+
* - IPv6 addresses: `http://[::1]:3000`, `https://[2001:db8::1]` (exact)
|
|
45
133
|
* - Combined: `https://*.fuz.dev:*`
|
|
46
134
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
135
|
+
* Refused, nothing normalized: anything but printable ASCII (punycode an
|
|
136
|
+
* international hostname), a scheme other than http or https (`null`,
|
|
137
|
+
* `file://`, `chrome-extension://`), a path, query, fragment or trailing
|
|
138
|
+
* slash, userinfo, a character no hostname holds, a partial wildcard, an IPv4
|
|
139
|
+
* address not written as four canonical decimal numbers (`127.1`), an IPv6
|
|
140
|
+
* address not in the form a browser sends, a port outside `1..=65535` or with
|
|
141
|
+
* leading zeros, the scheme's default port, and an empty entry. Every refused
|
|
142
|
+
* entry is reported, not just the first.
|
|
51
143
|
*
|
|
52
|
-
* @
|
|
144
|
+
* @param raw - the comma-separated allowlist value
|
|
145
|
+
* @returns the matchers, or every refusal — `no_origins` when the value is blank
|
|
53
146
|
*/
|
|
54
|
-
export const parse_allowed_origins = (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
147
|
+
export const parse_allowed_origins = (raw) => {
|
|
148
|
+
if (trim_ascii_whitespace(raw) === '') {
|
|
149
|
+
return { ok: false, errors: [{ kind: 'no_origins' }] };
|
|
150
|
+
}
|
|
151
|
+
const origins = [];
|
|
152
|
+
const errors = [];
|
|
153
|
+
raw.split(',').forEach((part, i) => {
|
|
154
|
+
const entry = trim_ascii_whitespace(part);
|
|
155
|
+
const parsed = origin_pattern_to_regexp(entry);
|
|
156
|
+
if (typeof parsed === 'string') {
|
|
157
|
+
errors.push({ kind: parsed, index: i + 1, entry });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
origins.push(parsed);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return errors.length > 0 ? { ok: false, errors } : { ok: true, origins };
|
|
164
|
+
};
|
|
61
165
|
/**
|
|
62
|
-
* Tests if
|
|
63
|
-
* Pattern matching is case-insensitive
|
|
166
|
+
* Tests if an `Origin` value matches any of the allowed patterns.
|
|
167
|
+
* Pattern matching is case-insensitive (web hosts and schemes are). A value
|
|
168
|
+
* that isn't visible ASCII matches nothing — a browser never sends one.
|
|
64
169
|
*/
|
|
65
|
-
export const should_allow_origin = (origin, allowed_patterns) => allowed_patterns.some((p) => p.test(origin));
|
|
170
|
+
export const should_allow_origin = (origin, allowed_patterns) => VISIBLE_ASCII.test(origin) && allowed_patterns.some((p) => p.test(origin));
|
|
66
171
|
/**
|
|
67
172
|
* Middleware that verifies the request source against an allowlist.
|
|
68
173
|
*
|
|
@@ -70,6 +175,9 @@ export const should_allow_origin = (origin, allowed_patterns) => allowed_pattern
|
|
|
70
175
|
* plus `http/simple_request.ts`):
|
|
71
176
|
* - Checks the `Origin` header (if present) against the allowlist
|
|
72
177
|
* - Allows requests without an `Origin` header (direct access, curl, etc.)
|
|
178
|
+
* - Refuses an `Origin` that isn't visible ASCII, and a duplicated one — the
|
|
179
|
+
* runtimes join a repeated header into one value (`a, b`), which carries a
|
|
180
|
+
* space and so matches nothing
|
|
73
181
|
*
|
|
74
182
|
* Origin-only by design — Fetch spec mandates `Origin` on every unsafe
|
|
75
183
|
* method (POST / PUT / DELETE / PATCH) regardless of `Referrer-Policy`,
|
|
@@ -78,126 +186,138 @@ export const should_allow_origin = (origin, allowed_patterns) => allowed_pattern
|
|
|
78
186
|
* attached session cookies, so CSRF isn't the relevant threat there —
|
|
79
187
|
* auth (bearer / daemon token) is the actual control. A Referer fallback
|
|
80
188
|
* would only widen the accepted-shape envelope without closing a real
|
|
81
|
-
* CSRF hole
|
|
189
|
+
* CSRF hole. The Rust spine's `origin_layer` is the twin.
|
|
190
|
+
*
|
|
191
|
+
* `create_app_server` mounts it on every path (`ORIGIN_MIDDLEWARE_PATH`); a
|
|
192
|
+
* request whose path a `carve_outs` entry matches passes unchecked — the named,
|
|
193
|
+
* explicit exception, each with its reason, as the Rust stack's
|
|
194
|
+
* `origin_carve_out` is.
|
|
82
195
|
*
|
|
83
196
|
* @param allowed_patterns - compiled regex patterns from `parse_allowed_origins`
|
|
197
|
+
* @param carve_outs - paths the check skips, matched like a middleware path (`middleware_applies`)
|
|
84
198
|
*/
|
|
85
|
-
export const verify_request_source = (allowed_patterns) => (c, next) => {
|
|
86
|
-
|
|
87
|
-
// Uses !== undefined so empty-string Origin headers are treated as
|
|
88
|
-
// present (abnormal, checked against allowlist — empty string never matches).
|
|
89
|
-
const origin = c.req.header('origin');
|
|
90
|
-
if (origin !== undefined) {
|
|
91
|
-
if (!should_allow_origin(origin, allowed_patterns)) {
|
|
92
|
-
return c.json({ error: ERROR_FORBIDDEN_ORIGIN }, 403);
|
|
93
|
-
}
|
|
199
|
+
export const verify_request_source = (allowed_patterns, carve_outs = []) => (c, next) => {
|
|
200
|
+
if (carve_outs.some((carve_out) => middleware_applies(carve_out.path, c.req.path))) {
|
|
94
201
|
return next();
|
|
95
202
|
}
|
|
96
|
-
//
|
|
97
|
-
//
|
|
203
|
+
// `!== undefined` so an empty-string Origin is present (abnormal, checked
|
|
204
|
+
// against the allowlist — the empty string never matches)
|
|
205
|
+
const origin = c.req.header('origin');
|
|
206
|
+
if (origin !== undefined && !should_allow_origin(origin, allowed_patterns)) {
|
|
207
|
+
return c.json({ error: ERROR_FORBIDDEN_ORIGIN }, 403);
|
|
208
|
+
}
|
|
209
|
+
// no Origin — direct access (curl, CLI); token auth is the control
|
|
98
210
|
return next();
|
|
99
211
|
};
|
|
100
212
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* Wildcard support:
|
|
106
|
-
* - Subdomain wildcards: `*.fuz.dev` matches `sub.fuz.dev` (NOT `fuz.dev`)
|
|
107
|
-
* - Multiple wildcards: `*.*.fuz.dev` matches `api.staging.fuz.dev`
|
|
108
|
-
* - Port wildcards: `fuz.dev:*` matches any port or no port
|
|
109
|
-
* - IPv6 support: `[::1]`, `[2001:db8::1]` (no wildcards in IPv6)
|
|
213
|
+
* Validates one trimmed entry and compiles it to a matcher, or names its
|
|
214
|
+
* refusal. The checks run in a fixed order and the first that fails names the
|
|
215
|
+
* kind — the Rust spine runs the same order, so both name the same kind.
|
|
110
216
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* - No wildcards in IPv6 addresses
|
|
115
|
-
* - Port wildcards must be `:*` exactly
|
|
116
|
-
*
|
|
117
|
-
* Note: Patterns are normalized via URL constructor. IPv4-mapped IPv6 addresses
|
|
118
|
-
* like `[::ffff:127.0.0.1]` will be normalized to `[::ffff:7f00:1]`. IPv6 zone
|
|
119
|
-
* identifiers (e.g., `%eth0`) are not supported.
|
|
120
|
-
*
|
|
121
|
-
* @throws Error if pattern format is invalid
|
|
217
|
+
* The compiled regex is `^scheme://host(:port)?$`, case-insensitive: an exact
|
|
218
|
+
* label matches itself, a `*` label `[^./:]+` (one non-empty label), a `:*`
|
|
219
|
+
* port `(:\d+)?`.
|
|
122
220
|
*/
|
|
123
|
-
const origin_pattern_to_regexp = (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
throw new Error(`Invalid origin pattern: ${pattern}`);
|
|
152
|
-
}
|
|
153
|
-
// Validate protocol is http or https
|
|
154
|
-
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
155
|
-
throw new Error(`Invalid origin pattern: ${pattern}`);
|
|
156
|
-
}
|
|
157
|
-
const hostname = url.hostname;
|
|
158
|
-
const is_ipv6 = hostname.startsWith('[');
|
|
159
|
-
// For regular hostnames, wildcards must be complete labels
|
|
160
|
-
if (!is_ipv6) {
|
|
161
|
-
for (const label of hostname.split('.')) {
|
|
162
|
-
if (label.includes('*') && label !== '*') {
|
|
163
|
-
throw new Error(`Wildcards must be complete labels (e.g., *.fuz.dev, not *fuz.dev): ${pattern}`);
|
|
164
|
-
}
|
|
221
|
+
const origin_pattern_to_regexp = (entry) => {
|
|
222
|
+
if (entry === '')
|
|
223
|
+
return 'empty_entry';
|
|
224
|
+
if (!VISIBLE_ASCII.test(entry))
|
|
225
|
+
return 'not_printable_ascii';
|
|
226
|
+
const scheme_end = entry.indexOf('://');
|
|
227
|
+
if (scheme_end === -1)
|
|
228
|
+
return 'missing_scheme';
|
|
229
|
+
const scheme = entry.slice(0, scheme_end).toLowerCase();
|
|
230
|
+
if (scheme !== 'http' && scheme !== 'https')
|
|
231
|
+
return 'unsupported_scheme';
|
|
232
|
+
const authority = entry.slice(scheme_end + 3);
|
|
233
|
+
if (/[/?#]/.test(authority))
|
|
234
|
+
return 'has_path';
|
|
235
|
+
if (authority.includes('@'))
|
|
236
|
+
return 'has_userinfo';
|
|
237
|
+
let host_source;
|
|
238
|
+
let port;
|
|
239
|
+
if (authority.startsWith('[')) {
|
|
240
|
+
const end = authority.indexOf(']');
|
|
241
|
+
if (end === -1)
|
|
242
|
+
return 'unclosed_ipv6';
|
|
243
|
+
const inner = authority.slice(1, end);
|
|
244
|
+
if (!is_ipv6_origin_form(inner))
|
|
245
|
+
return 'invalid_ipv6';
|
|
246
|
+
const rest = authority.slice(end + 1);
|
|
247
|
+
if (rest === '') {
|
|
248
|
+
port = null;
|
|
165
249
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
250
|
+
else if (rest.startsWith(':')) {
|
|
251
|
+
port = rest.slice(1);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
return 'invalid_after_ipv6';
|
|
255
|
+
}
|
|
256
|
+
host_source = escape_regexp(authority.slice(0, end + 1));
|
|
173
257
|
}
|
|
174
258
|
else {
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
259
|
+
const colon = authority.lastIndexOf(':');
|
|
260
|
+
const host = colon === -1 ? authority : authority.slice(0, colon);
|
|
261
|
+
port = colon === -1 ? null : authority.slice(colon + 1);
|
|
262
|
+
if (host === '')
|
|
263
|
+
return 'missing_host';
|
|
264
|
+
if (host.includes(':'))
|
|
265
|
+
return 'unbracketed_ipv6';
|
|
266
|
+
if (/[%\\^|<>[\]]/.test(host))
|
|
267
|
+
return 'invalid_host_char';
|
|
268
|
+
const labels = host.split('.');
|
|
269
|
+
if (labels.some((label) => label.includes('*') && label !== '*'))
|
|
270
|
+
return 'partial_wildcard';
|
|
271
|
+
if (!is_canonical_ipv4_or_name(host))
|
|
272
|
+
return 'non_canonical_ipv4';
|
|
273
|
+
host_source = labels
|
|
178
274
|
.map((label) => (label === '*' ? '[^./:]+' : escape_regexp(label)))
|
|
179
275
|
.join('\\.');
|
|
180
276
|
}
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
regex_pattern += '(:\\d+)?';
|
|
277
|
+
let port_source = '';
|
|
278
|
+
if (port === '*') {
|
|
279
|
+
port_source = '(?::\\d+)?';
|
|
185
280
|
}
|
|
186
|
-
else {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
281
|
+
else if (port !== null) {
|
|
282
|
+
if (!/^[1-9]\d*$/.test(port) || Number(port) > 65535)
|
|
283
|
+
return 'invalid_port';
|
|
284
|
+
if (port === (scheme === 'https' ? '443' : '80'))
|
|
285
|
+
return 'default_port';
|
|
286
|
+
port_source = ':' + port;
|
|
287
|
+
}
|
|
288
|
+
return new RegExp('^' + escape_regexp(scheme + '://') + host_source + port_source + '$', 'i');
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* True when `inner` (a bracketed host without its brackets) is an IPv6 address
|
|
292
|
+
* written exactly as a browser serializes it — lowercase-insensitive hex groups
|
|
293
|
+
* without leading zeros, the first longest run of two or more zero groups as
|
|
294
|
+
* `::`, no dotted-quad tail. The URL parser is the serializer here: an address
|
|
295
|
+
* it rewrites, or can't read, is refused rather than normalized.
|
|
296
|
+
*/
|
|
297
|
+
const is_ipv6_origin_form = (inner) => {
|
|
298
|
+
let hostname;
|
|
299
|
+
try {
|
|
300
|
+
hostname = new URL(`http://[${inner}]`).hostname;
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return false;
|
|
199
304
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
305
|
+
return hostname === `[${inner.toLowerCase()}]`;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* False when `host` (no brackets, wildcard labels allowed) is one a browser
|
|
309
|
+
* reads as an IPv4 address and then writes differently. A browser takes any
|
|
310
|
+
* host whose last label is a number — decimal or `0x` hex, one trailing dot
|
|
311
|
+
* aside — for an IPv4 address and sends it as four decimal numbers.
|
|
312
|
+
*/
|
|
313
|
+
const is_canonical_ipv4_or_name = (host) => {
|
|
314
|
+
const name = host.endsWith('.') ? host.slice(0, -1) : host;
|
|
315
|
+
const last = name.slice(name.lastIndexOf('.') + 1);
|
|
316
|
+
const is_number = /^0[xX][0-9a-fA-F]*$/.test(last) || /^\d+$/.test(last);
|
|
317
|
+
if (!is_number)
|
|
318
|
+
return true;
|
|
319
|
+
// a trailing dot makes a fifth, empty label
|
|
320
|
+
const labels = host.split('.');
|
|
321
|
+
return (labels.length === 4 &&
|
|
322
|
+
labels.every((label) => label === '*' || (/^(?:0|[1-9]\d{0,2})$/.test(label) && Number(label) <= 255)));
|
|
203
323
|
};
|
|
@@ -150,6 +150,27 @@ export interface RouteSpec {
|
|
|
150
150
|
* misleading `null` body.
|
|
151
151
|
*/
|
|
152
152
|
raw_body?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Marks a route that issues a credential — a session cookie — while
|
|
155
|
+
* declaring no auth itself: login, signup, bootstrap. A forged cross-site
|
|
156
|
+
* request to one is login CSRF, so it must take the origin check, and
|
|
157
|
+
* assembly refuses it outside the auth middleware's scope, where no origin
|
|
158
|
+
* carve-out can reach (`assert_credential_routes_in_auth_scope`). A route
|
|
159
|
+
* that reads a credential (`auth.account` not `'none'`) is held there
|
|
160
|
+
* without the mark.
|
|
161
|
+
*/
|
|
162
|
+
mints_credential?: boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Marks a route that reads the resolved credential in its handler while
|
|
165
|
+
* declaring no auth gate — it answers an anonymous caller itself instead
|
|
166
|
+
* of taking the dispatcher's `401` (account status, the cell-scoped fact
|
|
167
|
+
* read, the JSON-RPC endpoint whose dispatcher gates each action).
|
|
168
|
+
* Outside the auth middleware's scope no session or bearer parsing runs
|
|
169
|
+
* and it would see every caller as anonymous, so assembly refuses it
|
|
170
|
+
* there (`assert_credential_routes_in_auth_scope`), as it does a route
|
|
171
|
+
* whose `auth.account` is not `'none'`.
|
|
172
|
+
*/
|
|
173
|
+
reads_credential?: boolean;
|
|
153
174
|
/**
|
|
154
175
|
* Rate limit key type — declares what this route's rate limiter is keyed on.
|
|
155
176
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -106,6 +106,28 @@ export declare const schema_to_surface: (schema: z.ZodType) => unknown;
|
|
|
106
106
|
* - Exact match: `/health` matches `/health`
|
|
107
107
|
*/
|
|
108
108
|
export declare const middleware_applies: (mw_path: string, route_path: string) => boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Check if two middleware path patterns can match a common route path — the
|
|
111
|
+
* pattern-against-pattern form of `middleware_applies`, over the same
|
|
112
|
+
* grammar (`*`, an exact path, or a `/prefix/*` that also matches `/prefix`).
|
|
113
|
+
*
|
|
114
|
+
* @param a - one Hono-style pattern
|
|
115
|
+
* @param b - the other
|
|
116
|
+
*/
|
|
117
|
+
export declare const middleware_paths_overlap: (a: string, b: string) => boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Check if a middleware layer runs on a route path: its `path` pattern
|
|
120
|
+
* applies (`middleware_applies`) and none of its `carve_outs` does.
|
|
121
|
+
*
|
|
122
|
+
* @param spec - the layer's `path` and optional `carve_outs`
|
|
123
|
+
* @param route_path - the route path to check
|
|
124
|
+
*/
|
|
125
|
+
export declare const middleware_spec_applies: (spec: {
|
|
126
|
+
readonly path: string;
|
|
127
|
+
readonly carve_outs?: ReadonlyArray<{
|
|
128
|
+
readonly path: string;
|
|
129
|
+
}> | null;
|
|
130
|
+
}, route_path: string) => boolean;
|
|
109
131
|
/**
|
|
110
132
|
* Merge auto-derived, middleware, and explicit error schemas for a route spec.
|
|
111
133
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,OAAO,KAAG,OAUpD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,OAAO,KAAG,OACA,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EACnE,QAAQ,CAAC,EACT,OAAO,OAAO,KACZ,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAclC,CAAC;AAWF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAWtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,OAAO,KAAG,OAUpD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,OAAO,KAAG,OACA,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EACnE,QAAQ,CAAC,EACT,OAAO,OAAO,KACZ,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAclC,CAAC;AAWF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAM/D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM;IACL,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CACtE,EACD,YAAY,MAAM,KAChB,OAE0F,CAAC;AAE9F;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAWtB,CAAC"}
|
|
@@ -179,6 +179,30 @@ export const middleware_applies = (mw_path, route_path) => {
|
|
|
179
179
|
}
|
|
180
180
|
return false;
|
|
181
181
|
};
|
|
182
|
+
/**
|
|
183
|
+
* Check if two middleware path patterns can match a common route path — the
|
|
184
|
+
* pattern-against-pattern form of `middleware_applies`, over the same
|
|
185
|
+
* grammar (`*`, an exact path, or a `/prefix/*` that also matches `/prefix`).
|
|
186
|
+
*
|
|
187
|
+
* @param a - one Hono-style pattern
|
|
188
|
+
* @param b - the other
|
|
189
|
+
*/
|
|
190
|
+
export const middleware_paths_overlap = (a, b) => {
|
|
191
|
+
if (a === '*' || b === '*')
|
|
192
|
+
return true;
|
|
193
|
+
// a `/prefix/*` pattern's shortest match is the bare `/prefix` (`/*` → ``)
|
|
194
|
+
const base = (pattern) => pattern.endsWith('/*') ? pattern.slice(0, -2) : pattern;
|
|
195
|
+
return middleware_applies(a, base(b)) || middleware_applies(b, base(a));
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Check if a middleware layer runs on a route path: its `path` pattern
|
|
199
|
+
* applies (`middleware_applies`) and none of its `carve_outs` does.
|
|
200
|
+
*
|
|
201
|
+
* @param spec - the layer's `path` and optional `carve_outs`
|
|
202
|
+
* @param route_path - the route path to check
|
|
203
|
+
*/
|
|
204
|
+
export const middleware_spec_applies = (spec, route_path) => middleware_applies(spec.path, route_path) &&
|
|
205
|
+
!(spec.carve_outs ?? []).some((carve_out) => middleware_applies(carve_out.path, route_path));
|
|
182
206
|
/**
|
|
183
207
|
* Merge auto-derived, middleware, and explicit error schemas for a route spec.
|
|
184
208
|
*
|
package/dist/http/surface.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* App surface generation — JSON-serializable attack surface from route and middleware specs.
|
|
3
3
|
*
|
|
4
|
-
* Pure schema helpers (`is_null_schema`, `schema_to_surface`, `middleware_applies`,
|
|
4
|
+
* Pure schema helpers (`is_null_schema`, `schema_to_surface`, `middleware_applies`, `middleware_spec_applies`,
|
|
5
5
|
* `merge_error_schemas`) live in `http/schema_helpers.ts`.
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
@@ -52,6 +52,11 @@ export interface AppSurfaceMiddleware {
|
|
|
52
52
|
path: string;
|
|
53
53
|
/** JSON Schema representations of error responses, keyed by HTTP status code. `null` when none. */
|
|
54
54
|
error_schemas: Record<string, unknown> | null;
|
|
55
|
+
/** Paths under `path` the layer does not run on, each with its reason. Absent when none. */
|
|
56
|
+
carve_outs?: Array<{
|
|
57
|
+
path: string;
|
|
58
|
+
reason: string;
|
|
59
|
+
}>;
|
|
55
60
|
}
|
|
56
61
|
/** An env var in the generated attack surface (JSON-serializable). */
|
|
57
62
|
export interface AppSurfaceEnv {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAQ7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,qBAAqB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,WAAW,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,oFAAoF;IACpF,cAAc,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,uFAAuF;IACvF,aAAa,EAAE,OAAO,CAAC;IACvB,8FAA8F;IAC9F,YAAY,EAAE,OAAO,CAAC;IACtB,wFAAwF;IACxF,YAAY,EAAE,OAAO,CAAC;IACtB,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;IACvB,mGAAmG;IACnG,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED,wEAAwE;AACxE,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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"}
|