Compare commits

..
2 Commits
4 changed files with 20 additions and 15 deletions
+9 -7
View File
@@ -97,13 +97,15 @@ not for the public pages. See `docs/design-principles.md` for the design.
- `pagerite.js` — public page entry; runs fetch-navigation, scroll-reveal, - `pagerite.js` — public page entry; runs fetch-navigation, scroll-reveal,
brand shrink-to-fit (the themed size is the maximum; JS reduces the brand shrink-to-fit (the themed size is the maximum; JS reduces the
font-size so a long brand or narrow viewport still fits one line), font-size so a long brand or narrow viewport still fits one line),
code copy buttons, and the auth check: it fetches code copy buttons, and the auth check: it probes `GET /_api/settings`
`/auth/api/validate?perm=pagerite:admin` and only then injects the 🖊️ and only then injects the 🖊️ edit pens (asset URLs from the
edit pens (asset URLs from the `pagerite:editor-src`/`-css` meta tags); `pagerite:editor-src`/`-css` meta tags). The same reverse proxy that
a 401 adds a "log in" link to `/auth/` in the banner corner, a 403 gates `/_api` returns 401 for anonymous users, 403 for users without
nothing, and any other result (no auth server, e.g. dev) leaves the admin permission, and 200 for admins; a 401 adds a "log in" link
editing open. Pages themselves render identically for everyone; the to `/auth/` in the banner corner, a 403 nothing, and any other
real gate is the auth proxy in front of all of `/_api`. The backend links the shared CSS as two separate result (no auth proxy, e.g. dev) leaves editing open. Pages themselves
render identically for everyone; the real gate is the auth proxy in
front of all of `/_api`. The backend links the shared CSS as two separate
stylesheets (base and theme) so they can be swapped or augmented. stylesheets (base and theme) so they can be swapped or augmented.
- `assets/` — shared styles and data files built by Vite and served hashed - `assets/` — shared styles and data files built by Vite and served hashed
under `/_assets/`: `pagerite.css` (base layout + conservative variables), under `/_assets/`: `pagerite.css` (base layout + conservative variables),
+7 -5
View File
@@ -28,11 +28,13 @@
// --- Auth-gated edit pens --------------------------------------------- // --- Auth-gated edit pens ---------------------------------------------
// Pages render identically for everyone; the 🖊️ pens are injected by JS // Pages render identically for everyone; the 🖊️ pens are injected by JS
// only after the auth server validates the session (perm pagerite:admin). // only after we know the user has pagerite:admin access. We probe our own
// /_api/settings endpoint: the same reverse proxy that gates /_api returns
// 401/403 here, and a 200 means the permission is present.
// 401 = anonymous: show a small login link in the banner corner instead. // 401 = anonymous: show a small login link in the banner corner instead.
// 403 = logged in without the permission: no pens. Any other outcome // 403 = logged in without the permission: no pens. Any other outcome
// (404, network error — i.e. no auth server deployed, as in dev) leaves // (network error — i.e. no auth proxy deployed, as in dev) leaves editing
// editing open as before: the real gate is the proxy in front of /_api. // open as before: the real gate is the proxy in front of /_api.
let authorized = false; let authorized = false;
let editorMeta = null; let editorMeta = null;
@@ -78,9 +80,9 @@
}; };
let status = 0; let status = 0;
try { try {
status = (await fetch("/auth/api/validate?perm=pagerite:admin")).status; status = (await fetch("/_api/settings")).status;
} catch { } catch {
// Auth server unreachable: treat as not deployed. // Auth proxy unreachable: treat as not deployed.
} }
if (status === 401) addLoginLink(); if (status === 401) addLoginLink();
else if (status !== 403) { else if (status !== 403) {
+3 -2
View File
@@ -563,8 +563,9 @@ async def show_page(request: Request, path: str) -> HTMLResponse | Response:
""" """
path = path.strip("/") path = path.strip("/")
if path and _is_reserved(path): if path and _is_reserved(path):
# Reserved slug shape: never content — no tree lookup. # Invalid slug shape: not a content URL, let FastAPI return its
return HTMLResponse(views.render_not_found(data.menu, path, data.brand, data.custom_css, data.theme), 404) # built-in 404 instead of rendering an editable article page.
raise HTTPException(404)
chain = resolve(data.menu, path) chain = resolve(data.menu, path)
node = chain[-1] if chain else None node = chain[-1] if chain else None
if node is not None and node.published and node.content is not None: if node is not None and node.published and node.content is not None:
+1 -1
View File
@@ -353,7 +353,7 @@ def render_not_found(
doc = E.article doc = E.article
with doc: with doc:
doc.h1("Not Found") doc.h1("Not Found")
doc.p(f"No page at /{path}.") doc.p(f"No article at /{path}. If there was before, it may have been deleted.")
scripts, styles = _page_assets(theme) scripts, styles = _page_assets(theme)
return str( return str(
_layout(styles, scripts, custom_css, theme)( _layout(styles, scripts, custom_css, theme)(