caspian-utils 0.2.1 → 0.2.2
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/docs/auth.md
CHANGED
|
@@ -305,21 +305,22 @@ Because Starlette runs the last-added middleware first, the effective request or
|
|
|
305
305
|
5. `RPCMiddleware`
|
|
306
306
|
6. route handler or RPC endpoint
|
|
307
307
|
|
|
308
|
-
Current behavior by layer:
|
|
309
|
-
|
|
310
|
-
- `SecurityHeadersMiddleware` can attach baseline response headers from `casp.runtime_security`, such as `X-Content-Type-Options`, framing policy, referrer policy, permissions policy, and production HSTS, while preserving any headers already set by the response. Do not assume this layer emits CSP or owns third-party browser resource allowlists; verify the installed package helper first.
|
|
311
|
-
- `
|
|
308
|
+
Current behavior by layer:
|
|
309
|
+
|
|
310
|
+
- `SecurityHeadersMiddleware` can attach baseline response headers from `casp.runtime_security`, such as `X-Content-Type-Options`, framing policy, referrer policy, permissions policy, and production HSTS, while preserving any headers already set by the response. Do not assume this layer emits CSP or owns third-party browser resource allowlists; verify the installed package helper first.
|
|
311
|
+
- `PublicFilesMiddleware` serves any existing `GET`/`HEAD` file under `public/**` before rate limiting, sessions, CSRF, auth, RPC, or page routing. It falls through for missing files and preserves restricted inline-media handling for configured upload directories.
|
|
312
|
+
- `SessionMiddleware` provides `request.session` for the rest of the stack.
|
|
312
313
|
- `CSRFMiddleware` ensures `request.session["csrf_token"]` exists and emits a scoped CSRF cookie based on `pp_csrf`, for example `pp_csrf_5091` in development or plain `pp_csrf` when no dev scope is active.
|
|
313
|
-
- `AuthMiddleware` sets request context with `Auth.set_request(request)`, initializes `StateManager`, runs provider callbacks,
|
|
314
|
+
- `AuthMiddleware` sets request context with `Auth.set_request(request)`, initializes `StateManager`, runs provider callbacks, and enforces public, auth, private, and role-based route redirects. Existing public files never reach it because `PublicFilesMiddleware` serves them first.
|
|
314
315
|
- `RPCMiddleware` handles `POST` requests with `X-PP-RPC: true` and forwards them to Caspian's RPC handler after auth and session setup are already available.
|
|
315
316
|
|
|
316
317
|
Keep `SessionMiddleware` immediately inside any outer response-header wrapper such as `SecurityHeadersMiddleware`. If CSRF, auth, or RPC handling runs before the session layer, `request.session` will not be available.
|
|
317
318
|
|
|
318
319
|
## Current `AuthMiddleware` Flow
|
|
319
320
|
|
|
320
|
-
The pasted `main.py` auth middleware currently behaves like this:
|
|
321
|
-
|
|
322
|
-
-
|
|
321
|
+
The pasted `main.py` auth middleware currently behaves like this:
|
|
322
|
+
|
|
323
|
+
- receives no request for an existing public file because the outer `PublicFilesMiddleware` has already served it; missing paths continue through normal auth and routing behavior
|
|
323
324
|
- initializes request-bound auth state with `StateManager.init(request)` and `Auth.set_request(request)`
|
|
324
325
|
- runs OAuth provider signin and callback handling before public or private route checks
|
|
325
326
|
- lets public routes through immediately
|
|
@@ -39,7 +39,7 @@ Important current `main.py` behaviors AI should keep in mind:
|
|
|
39
39
|
- `register_single_route(...)` passes path params to `page()` as one positional dict, injects matching query params by name, and injects `request` by keyword when declared.
|
|
40
40
|
- The render pipeline is `transform_components(...)`, then `render_with_nested_layouts(...)`, then `transform_scripts(...)`.
|
|
41
41
|
- Route-level generators returned from `page()` are wrapped in `SSE(...)` before the response is sent.
|
|
42
|
-
- Safe public-file helpers live in `casp.runtime_security`
|
|
42
|
+
- Safe public-file helpers live in `casp.runtime_security`. `PublicFilesMiddleware` maps every existing nested file under `public/**` to the same root-relative URL without per-directory routes, rejects traversal and symlink escape, handles only `GET`/`HEAD`, and falls through when no file exists so page and mounted-app routing still works. User-upload directories must retain their restricted inline-media policy.
|
|
43
43
|
- Session middleware secrets may be resolved through `casp.runtime_security` so production can fail fast when `AUTH_SECRET` is missing or still on a default placeholder.
|
|
44
44
|
- Baseline response headers are built by `casp.runtime_security` and attached through `SecurityHeadersMiddleware`. That set now includes a Content-Security-Policy from `build_content_security_policy()`, which the `CONTENT_SECURITY_POLICY` environment variable replaces wholesale. The policy must keep `'unsafe-eval'` and `'unsafe-inline'` in `script-src`, because the PulsePoint runtime compiles templates with `new Function`; read the current helper before tightening it. Outside production the helper also adds loopback origins to `connect-src` so the BrowserSync live-reload client, which polls a different port than the proxied page, is not blocked; an environment override replaces that too.
|
|
45
45
|
- Middleware is added in source order as `RPCMiddleware`, `AuthMiddleware`, `CSRFMiddleware`, `SessionMiddleware`, `BodySizeLimitMiddleware`, `RateLimitMiddleware`, `SecurityHeadersMiddleware`, plus `RequestDiagnosticsMiddleware` outside production. The effective request order is reversed at runtime, so security headers and the rate limit run first and `RPCMiddleware` runs last. Verify the current list in `main.py` rather than trusting this order.
|
|
@@ -180,9 +180,14 @@ This folder contains your database model definitions in `schema.prisma` and any
|
|
|
180
180
|
|
|
181
181
|
### `public/`
|
|
182
182
|
|
|
183
|
-
Store static assets here, including images, fonts, and generated frontend assets that should be served directly.
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
Store static assets here, including images, fonts, and generated frontend assets that should be served directly.
|
|
184
|
+
|
|
185
|
+
The public root maps directly to the URL root. Any existing nested file is
|
|
186
|
+
available at the same root-relative URL—for example,
|
|
187
|
+
`public/icons/app.png` is served as `/icons/app.png`. Adding a public
|
|
188
|
+
subdirectory does not require a matching route or mount in `main.py`.
|
|
189
|
+
|
|
190
|
+
Runtime-uploaded public blobs can also live here. Confirm the actual upload path in the project code, commonly `public/uploads/`, and keep that directory aligned with any BrowserSync ignore rules.
|
|
186
191
|
|
|
187
192
|
If the upload directory is created only at runtime, create it on demand in the owning upload helper instead of assuming it is already committed.
|
|
188
193
|
|
|
@@ -218,7 +223,14 @@ Use this package module when the task is about:
|
|
|
218
223
|
- user-facing vs production-safe exception messaging helpers
|
|
219
224
|
- baseline response headers such as permissions, referrer, MIME sniffing, framing, or HSTS behavior
|
|
220
225
|
|
|
221
|
-
Because this file is framework-owned, edit it only for Caspian runtime work or when documentation must match the installed package. App-specific auth policy still belongs in `src/lib/auth/auth_config.py`, and app-specific upload or storage behavior should live in route-owned code or other `src/lib/**` helpers.
|
|
226
|
+
Because this file is framework-owned, edit it only for Caspian runtime work or when documentation must match the installed package. App-specific auth policy still belongs in `src/lib/auth/auth_config.py`, and app-specific upload or storage behavior should live in route-owned code or other `src/lib/**` helpers.
|
|
227
|
+
|
|
228
|
+
`PublicFilesMiddleware` serves only existing `GET`/`HEAD` files that resolve
|
|
229
|
+
inside the configured public root and falls through for every other request.
|
|
230
|
+
Install it inside the security-header layer and outside rate limiting, sessions,
|
|
231
|
+
CSRF, auth, RPC, and page routing. Preserve a restricted inline-media policy for
|
|
232
|
+
user-upload directories so executable uploads such as HTML and SVG download
|
|
233
|
+
instead of rendering with the application's origin.
|
|
222
234
|
|
|
223
235
|
### `caspian.config.json`
|
|
224
236
|
|
|
@@ -62,7 +62,7 @@ The script is composed so the export always runs against a **fresh route/compone
|
|
|
62
62
|
|
|
63
63
|
- boots the real ASGI app in-process and requests every route through Starlette's `TestClient`, so exported HTML is byte-identical to what the dev server serves (layouts, components, PulsePoint deferral, security headers — the whole pipeline),
|
|
64
64
|
- writes each page to `static/<route>/index.html` (`/` → `static/index.html`),
|
|
65
|
-
- mirrors public
|
|
65
|
+
- mirrors the complete `public/**` tree into `static/`, including app-defined directories such as `icons` and `fonts`,
|
|
66
66
|
- runs in `APP_ENV=development` so the build does not require production secrets.
|
|
67
67
|
|
|
68
68
|
**Scope policy is "warn & skip"** — anything that cannot be fully static is reported and NOT written, so nothing broken ships silently:
|