From 4bccf6855eb442c147788f353de8cb2e973de71d Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Fri, 18 Sep 2026 20:14:52 +0000 Subject: [PATCH] Auth via paskia-js: profile() dialog, apiFetch/apiJson in admin components - Banner-corner auth link is now a button opening paskia-js's profile() dialog (handles login too); auth re-probed when the dialog closes. - Editor/analytics components call /_api via apiFetch/apiJson: an expired session opens the login dialog and the request retries. - pagerite.js: task-checkbox toggle uses apiJson (explicit edit attempt, reverts on any failure incl. cancelled login); auth probes use fetchJson (never a dialog); page-cache/navigation stay on plain fetch. - Add the paskia npm dependency; document the convention. --- AGENTS.md | 2 +- docs/frontend-runtime.md | 4 +- frontend/package.json | 1 + frontend/src/AnalyticsView.vue | 4 +- frontend/src/BannerEditor.vue | 5 ++- frontend/src/EditorShell.vue | 3 +- frontend/src/LocalizationEditor.vue | 13 +++--- frontend/src/PageEditor.vue | 5 ++- frontend/src/SiteEditor.vue | 17 ++++---- frontend/src/StructureEditor.vue | 11 ++--- frontend/src/assets/pagerite.css | 6 +-- frontend/src/pagerite.js | 65 ++++++++++++++++------------- frontend/src/swapdoc.js | 4 +- 13 files changed, 80 insertions(+), 60 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d78adc9..925cb99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,5 +67,5 @@ Server run by CLI entry point `uv run pagerite` (no auto reloads, build needed). - Keep dependencies minimal; add via `uv add` and mention it. - The public URL space belongs to content (pretty slugs at root). Reserve only `/_` for the machinery (`/_api/`, `/_f/`, `/_assets/`), plus `/favicon.ico` (backend redirect to the configured site icon). Slugs are lowercase ASCII letters, digits, hyphens and underscores `[a-z0-9_-]` (the site editor filters input live via `slugify.js`, built on the `transliteration` npm package — unicode folds to ASCII, spaces become hyphens; an empty slug on a new page is derived from its title), may not begin with `_` or `.`, and such URLs are never looked up as content. -- No auth in core code; the SSO/reverse proxy gates all of `/_api` (forward-auth) and owns `/auth/` (login/logout, session validation). Pages render identically for everyone; pagerite.js adds the editing UI only after the auth server validates the session. The one keyed exception is `/_translate/{key}` (translator service; `Data.translate_keys`, see docs/localization.md). +- No auth in core code; the SSO/reverse proxy gates all of `/_api` (forward-auth) and owns `/auth/` (login/logout, session validation). Pages render identically for everyone; pagerite.js adds the editing UI only after the auth server validates the session. The one keyed exception is `/_translate/{key}` (translator service; `Data.translate_keys`, see docs/localization.md). Admin components use the paskia npm package's `apiFetch`/`apiJson` for `/_api` calls (login dialog + retry on expired sessions); pagerite.js uses `apiJson` only for the task-checkbox toggle (an explicit edit attempt) and `fetchJson` for its auth probes — never `apiFetch` there, so anonymous visitors never get a login popup. - Update the relevant MarkDown files when architecture, tooling, or conventions change. diff --git a/docs/frontend-runtime.md b/docs/frontend-runtime.md index c3c011a..5c86b46 100644 --- a/docs/frontend-runtime.md +++ b/docs/frontend-runtime.md @@ -10,7 +10,9 @@ Vue editor app entry, mounts the tabbed `EditorShell`. See `docs/editing.md` for Public page entry; runs fetch-navigation (backed by an in-memory page cache: every visible internal link is fetched once at load and clicks are then served from JS with no fetch — the current page itself is not refetched, it enters the cache when navigated to — and the editors' `loadPlain` keeps the cache current via a `pagerite:page-fetched` event; articles are `cache-control: no-cache` on the wire). Editors can drop the entire cache with the `pagerite:drop-page-cache` event when site-wide or page changes (theme, headings, structure, banners, etc.) invalidate the cached HTML of other pages; `main.js` triggers a fresh `pagerite:preload-pages` pass when the editor panel closes so navigation is fast again. Navigation that starts while the editor is open bypasses the cache and fetches the target page on demand. Also runs scroll-reveal, a scroll-driven section hash (the location hash tracks the h1/h2 above the viewport middle via replaceState — removed above the first tagged heading and at the very top, never set on unscrollable pages), OverlayScrollbars on `document.body` (floating, auto-hiding scrollbars that never reserve layout space or shift the page when appearing; native scroll APIs like `window.scrollTo` keep working; themed via the `--os-*` variables in pagerite.css), 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), nav condense-to-fit (the top nav stays on one row: link gaps shrink first, then the side padding, then the font size; `flex-wrap: wrap` remains the no-JS fallback), code copy buttons, click-to-enlarge on article figure images (a full-viewport lightbox with the caption, closed by click or Esc), and the auth check. -It first probes `GET /auth/api/settings` to detect whether Paskia SSO is available, then `GET /_api/settings` to learn the current session's admin status. The same reverse proxy that gates `/_api` returns 401 for anonymous users, 403 for users without the admin permission, and 200 for admins. When Paskia is detected, a login link (anonymous) or profile link (logged in) is shown in the banner corner; both are plain `` links (Paskia does not support being iframed, so we navigate normally), and a `pageshow` handler re-probes auth when history navigation restores a cached page. Admins also get the page/banner edit pens and a site-settings pen, plus a `modulepreload` warm-up of the editor bundle (the hashed asset is immutable, so it costs nothing). If no Paskia SSO is detected (dev/no proxy), editing is left open. Pages themselves render identically for everyone; the real gate is the auth proxy in front of all of `/_api`. +It first probes `GET /auth/api/settings` to detect whether Paskia SSO is available, then `GET /_api/settings` to learn the current session's admin status. The same reverse proxy that gates `/_api` returns 401 for anonymous users, 403 for users without the admin permission, and 200 for admins. When Paskia is detected, a login button (anonymous) or profile button (logged in) is shown in the banner corner; clicking it opens the paskia-js `profile()` dialog (an iframe overlay served by Paskia itself, which also runs the login flow), and auth is re-probed when the dialog closes. A `pageshow` handler also re-probes auth when history navigation restores a cached page. Admins also get the page/banner edit pens and a site-settings pen, plus a `modulepreload` warm-up of the editor bundle (the hashed asset is immutable, so it costs nothing). If no Paskia SSO is detected (dev/no proxy), editing is left open. Pages themselves render identically for everyone; the real gate is the auth proxy in front of all of `/_api`. + +The editor/analytics components (everything except pagerite.js and main.js) make their `/_api` calls through paskia-js's `apiFetch`/`apiJson` instead of plain `fetch`: when a call gets a 401/403 carrying an `auth.iframe` hint (expired session), the login dialog opens in place and the request retries transparently after authentication. pagerite.js uses `apiJson` only for the task-checkbox toggle (ticking a box is an explicit edit attempt, so a login dialog is welcome there; any failure — including a cancelled login — reverts the checkbox) and `fetchJson` for its auth probes (plain fetch with JSON handling and errors on non-OK, never a dialog); page-cache and navigation fetches stay on plain `fetch`, so anonymous visitors never get a login popup uninvited. Asset wiring differs by mode. In dev the backend links the Vite dev-server URLs (`pagerite:editor-src`/`-css`/`pagerite:analytics-src` meta tags, `` stylesheets) and Vite injects the entry CSS from JS for hot reloads. In production there are no pagerite meta tags: all page assets are inlined into the document — stylesheets as `