From c05fc376f2e6b35e0214985ccbd3fb384d0c6dc7 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Tue, 2 Jun 2026 14:01:29 -0500 Subject: [PATCH] chore(embedded): cut v0.0.27-beta --- zddc/internal/apps/embedded/archive.html | 134 ++++++++++------ zddc/internal/apps/embedded/browse.html | 158 ++++++++++++------- zddc/internal/apps/embedded/classifier.html | 134 ++++++++++------ zddc/internal/apps/embedded/index.html | 134 ++++++++++------ zddc/internal/apps/embedded/transmittal.html | 134 ++++++++++------ zddc/internal/apps/embedded/versions.txt | 14 +- zddc/internal/handler/tables.html | 134 ++++++++++------ 7 files changed, 529 insertions(+), 313 deletions(-) diff --git a/zddc/internal/apps/embedded/archive.html b/zddc/internal/apps/embedded/archive.html index c2f582a..019f720 100644 --- a/zddc/internal/apps/embedded/archive.html +++ b/zddc/internal/apps/embedded/archive.html @@ -2582,7 +2582,7 @@ td[data-field="trackingNumber"] {
ZDDC Archive - v0.0.27-beta · 2026-06-01 18:30:53 · 5ed4f85 + v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4
@@ -10740,23 +10740,26 @@ window.app.modules.filtering = { } }()); -// shared/elevation.js — admin elevation toggle. +// shared/elevation.js — admin elevation via URL toggle. // -// Sudo-style model: admins behave as normal users by default; clicking -// the header toggle elevates the session so admin escape hatches (WORM -// bypass, .zddc edit authority, profile admin scaffolds) start firing. -// State is carried in a `zddc-elevate=1` cookie that the server reads -// via handler.ACLMiddleware → zddc.Principal{Elevated}. +// Sudo-style model: admins behave as normal users by default; elevating +// the session turns on admin escape hatches (WORM bypass, .zddc edit +// authority, profile admin scaffolds). State is carried in a +// `zddc-elevate=1` cookie that the server reads via handler.ACLMiddleware +// → zddc.Principal{Elevated}. // -// Only renders the toggle when /.profile/access reports the caller has -// some admin scope — a non-admin sees nothing, which keeps the chrome -// quiet for the common case. The toggle fades in once access loads so -// non-admins never even see the affordance flash. +// Toggle is by URL query param — `?admin=true` to arm, `?admin=false` +// (or the red banner's "Drop admin" button) to drop — so it's reachable +// from ANY zddc-server page, not just ones that render a header control. +// The cookie is the sticky state: it persists across navigation for its +// Max-Age window, so the param need not stay in the URL (we strip it). +// Arming is gated on /.profile/access `can_elevate`, so only real admins +// can set it; a non-admin's ?admin=true is a silent no-op. // -// Click flow: set/clear the cookie, then reload the page so the server -// sees the new state on the next render. The reload is intentional — -// admin scaffolds in tool HTML are server-rendered for some tools, so -// a soft state flip on the client alone wouldn't reach those. +// Applying the cookie reloads to the cleaned URL so the server re-renders +// under the new state (admin scaffolds in some tool HTML are server- +// rendered, so a client-only flip wouldn't reach them). The red viewport +// border + banner (applyArmedChrome) reflect the cookie on every load. (function () { 'use strict'; @@ -10801,22 +10804,65 @@ window.app.modules.filtering = { } } - function render(host, elevated) { - host.classList.remove('hidden'); - host.innerHTML = - '' - + ''; - var cb = host.querySelector('#elevation-checkbox'); - cb.addEventListener('change', function () { - setElevated(cb.checked); - // Hard reload so server-rendered admin surfaces (profile - // page scaffolds, hidden-entry listings) catch up. URL - // and scroll state are preserved by the browser's normal - // back-forward cache rules. - window.location.reload(); - }); + // ── URL toggle: ?admin=true | ?admin=false (typeable anywhere) ────── + // + // Admin mode is toggled via a URL query param rather than an on-screen + // checkbox, so it's reachable from any zddc-server page. The param only + // SETS the cookie; the cookie is the sticky state (it persists across + // navigation for its Max-Age window and is what the server reads), so + // there's no need to keep ?admin= in the URL once applied. + + // adminParam returns true/false for a recognised ?admin= value, or null + // when absent / unrecognised (ignored). + function adminParam() { + try { + var v = new URLSearchParams(window.location.search).get('admin'); + if (v === null) return null; + v = v.toLowerCase(); + if (v === 'true' || v === '1' || v === 'on' || v === 'yes') return true; + if (v === 'false' || v === '0' || v === 'off' || v === 'no') return false; + return null; + } catch (_e) { return null; } + } + + // urlWithoutAdmin returns the current URL with the admin param stripped + // (other params + hash preserved) — what we navigate/replace to so the + // dirty param isn't bookmarked and Back doesn't re-trigger it. + function urlWithoutAdmin() { + var u = new URL(window.location.href); + u.searchParams.delete('admin'); + var qs = u.searchParams.toString(); + return u.pathname + (qs ? '?' + qs : '') + u.hash; + } + + // handleAdminParam applies a ?admin= request. Returns true when a + // navigation (reload) is underway so the caller can stop. Enabling is + // gated on can_elevate — a non-admin who types ?admin=true just gets + // the param stripped, never a misleading red border. Disabling is open + // (anyone may drop a cookie they somehow hold). + async function handleAdminParam() { + var want = adminParam(); + if (want === null) return false; + var clean = urlWithoutAdmin(); + if (want === isElevated()) { + // Already in the requested state — just clean the URL, no reload. + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + if (want === true) { + var access = await fetchAccess(); + if (!access || !access.can_elevate) { + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + setElevated(true); + } else { + setElevated(false); + } + // Navigate to the clean URL (a real load, so the server re-renders + // under the new cookie) and replace history so Back is safe. + window.location.replace(clean); + return true; } // Page-wide affordances when elevation is active. The toggle alone @@ -10858,26 +10904,16 @@ window.app.modules.filtering = { } async function init() { - // Body chrome applies on every page load whether or not the - // header has a toggle slot — the banner needs to surface in - // tools / pages that don't host the toggle (e.g. iframed - // classifier inside browse's grid mode), so the user can't - // accidentally write through an elevated context elsewhere. + // Apply (or tear down) the red border + banner from the cookie on + // every page load — admin mode is toggled by URL, but the armed + // chrome must surface everywhere so the user can't accidentally + // write through an elevated context on a page they didn't toggle. applyArmedChrome(isElevated()); - var host = document.getElementById('elevation-toggle'); - if (!host) return; // tool doesn't include the slot yet — no-op - var access = await fetchAccess(); - if (!access) return; // anonymous / endpoint missing — no-op - // Surface ONLY for users who have admin authority somewhere. - // /.profile/access ships `can_elevate` as an elevation- - // INDEPENDENT signal — true for any user named in any admin - // list, regardless of current cookie state. The other flags - // (is_super_admin, has_any_admin_scope) reflect EFFECTIVE - // authority and would be false for an un-elevated admin - // who hasn't toggled yet — so we can't gate on those. - if (!access.can_elevate) return; - render(host, isElevated()); + // Honour ?admin=true|false typed into any zddc-server URL. There's + // no on-screen toggle anymore — the URL is the enable path and the + // red banner's "Drop admin" button is the one-click disable. + await handleAdminParam(); } if (document.readyState === 'loading') { diff --git a/zddc/internal/apps/embedded/browse.html b/zddc/internal/apps/embedded/browse.html index db04d6a..976946d 100644 --- a/zddc/internal/apps/embedded/browse.html +++ b/zddc/internal/apps/embedded/browse.html @@ -2476,7 +2476,7 @@ body {
ZDDC Browse - v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85 + v0.0.27-beta · 2026-06-02 19:01:23 · af07fa4
@@ -5967,23 +5967,26 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr window.zddc.menu = { open: open, close: close }; })(); -// shared/elevation.js — admin elevation toggle. +// shared/elevation.js — admin elevation via URL toggle. // -// Sudo-style model: admins behave as normal users by default; clicking -// the header toggle elevates the session so admin escape hatches (WORM -// bypass, .zddc edit authority, profile admin scaffolds) start firing. -// State is carried in a `zddc-elevate=1` cookie that the server reads -// via handler.ACLMiddleware → zddc.Principal{Elevated}. +// Sudo-style model: admins behave as normal users by default; elevating +// the session turns on admin escape hatches (WORM bypass, .zddc edit +// authority, profile admin scaffolds). State is carried in a +// `zddc-elevate=1` cookie that the server reads via handler.ACLMiddleware +// → zddc.Principal{Elevated}. // -// Only renders the toggle when /.profile/access reports the caller has -// some admin scope — a non-admin sees nothing, which keeps the chrome -// quiet for the common case. The toggle fades in once access loads so -// non-admins never even see the affordance flash. +// Toggle is by URL query param — `?admin=true` to arm, `?admin=false` +// (or the red banner's "Drop admin" button) to drop — so it's reachable +// from ANY zddc-server page, not just ones that render a header control. +// The cookie is the sticky state: it persists across navigation for its +// Max-Age window, so the param need not stay in the URL (we strip it). +// Arming is gated on /.profile/access `can_elevate`, so only real admins +// can set it; a non-admin's ?admin=true is a silent no-op. // -// Click flow: set/clear the cookie, then reload the page so the server -// sees the new state on the next render. The reload is intentional — -// admin scaffolds in tool HTML are server-rendered for some tools, so -// a soft state flip on the client alone wouldn't reach those. +// Applying the cookie reloads to the cleaned URL so the server re-renders +// under the new state (admin scaffolds in some tool HTML are server- +// rendered, so a client-only flip wouldn't reach them). The red viewport +// border + banner (applyArmedChrome) reflect the cookie on every load. (function () { 'use strict'; @@ -6028,22 +6031,65 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr } } - function render(host, elevated) { - host.classList.remove('hidden'); - host.innerHTML = - '' - + ''; - var cb = host.querySelector('#elevation-checkbox'); - cb.addEventListener('change', function () { - setElevated(cb.checked); - // Hard reload so server-rendered admin surfaces (profile - // page scaffolds, hidden-entry listings) catch up. URL - // and scroll state are preserved by the browser's normal - // back-forward cache rules. - window.location.reload(); - }); + // ── URL toggle: ?admin=true | ?admin=false (typeable anywhere) ────── + // + // Admin mode is toggled via a URL query param rather than an on-screen + // checkbox, so it's reachable from any zddc-server page. The param only + // SETS the cookie; the cookie is the sticky state (it persists across + // navigation for its Max-Age window and is what the server reads), so + // there's no need to keep ?admin= in the URL once applied. + + // adminParam returns true/false for a recognised ?admin= value, or null + // when absent / unrecognised (ignored). + function adminParam() { + try { + var v = new URLSearchParams(window.location.search).get('admin'); + if (v === null) return null; + v = v.toLowerCase(); + if (v === 'true' || v === '1' || v === 'on' || v === 'yes') return true; + if (v === 'false' || v === '0' || v === 'off' || v === 'no') return false; + return null; + } catch (_e) { return null; } + } + + // urlWithoutAdmin returns the current URL with the admin param stripped + // (other params + hash preserved) — what we navigate/replace to so the + // dirty param isn't bookmarked and Back doesn't re-trigger it. + function urlWithoutAdmin() { + var u = new URL(window.location.href); + u.searchParams.delete('admin'); + var qs = u.searchParams.toString(); + return u.pathname + (qs ? '?' + qs : '') + u.hash; + } + + // handleAdminParam applies a ?admin= request. Returns true when a + // navigation (reload) is underway so the caller can stop. Enabling is + // gated on can_elevate — a non-admin who types ?admin=true just gets + // the param stripped, never a misleading red border. Disabling is open + // (anyone may drop a cookie they somehow hold). + async function handleAdminParam() { + var want = adminParam(); + if (want === null) return false; + var clean = urlWithoutAdmin(); + if (want === isElevated()) { + // Already in the requested state — just clean the URL, no reload. + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + if (want === true) { + var access = await fetchAccess(); + if (!access || !access.can_elevate) { + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + setElevated(true); + } else { + setElevated(false); + } + // Navigate to the clean URL (a real load, so the server re-renders + // under the new cookie) and replace history so Back is safe. + window.location.replace(clean); + return true; } // Page-wide affordances when elevation is active. The toggle alone @@ -6085,26 +6131,16 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr } async function init() { - // Body chrome applies on every page load whether or not the - // header has a toggle slot — the banner needs to surface in - // tools / pages that don't host the toggle (e.g. iframed - // classifier inside browse's grid mode), so the user can't - // accidentally write through an elevated context elsewhere. + // Apply (or tear down) the red border + banner from the cookie on + // every page load — admin mode is toggled by URL, but the armed + // chrome must surface everywhere so the user can't accidentally + // write through an elevated context on a page they didn't toggle. applyArmedChrome(isElevated()); - var host = document.getElementById('elevation-toggle'); - if (!host) return; // tool doesn't include the slot yet — no-op - var access = await fetchAccess(); - if (!access) return; // anonymous / endpoint missing — no-op - // Surface ONLY for users who have admin authority somewhere. - // /.profile/access ships `can_elevate` as an elevation- - // INDEPENDENT signal — true for any user named in any admin - // list, regardless of current cookie state. The other flags - // (is_super_admin, has_any_admin_scope) reflect EFFECTIVE - // authority and would be false for an un-elevated admin - // who hasn't toggled yet — so we can't gate on those. - if (!access.can_elevate) return; - render(host, isElevated()); + // Honour ?admin=true|false typed into any zddc-server URL. There's + // no on-screen toggle anymore — the URL is the enable path and the + // red banner's "Drop admin" button is the one-click disable. + await handleAdminParam(); } if (document.readyState === 'loading') { @@ -11742,8 +11778,8 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // equivalent. // // Talks to the zddc-server history endpoints on the file's own URL: -// GET ?history=1 → JSON [{ts, by, sha, prev, bytes, current}] -// GET ?history= → that version's raw bytes +// GET ?history=1 → JSON [{ts, by, id, bytes, current}] +// GET ?history= → that version's raw bytes (id = snapshot filename) // Restore re-PUTs a chosen version's bytes to , which the server // records as a new version (forward-only; never destructive). // @@ -11803,8 +11839,8 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr return Array.isArray(data) ? data : []; } - async function fetchVersion(node, sha) { - var resp = await fetch(histURL(node.url, sha), { credentials: 'same-origin' }); + async function fetchVersion(node, id) { + var resp = await fetch(histURL(node.url, id), { credentials: 'same-origin' }); if (!resp.ok) throw new Error('HTTP ' + resp.status); return await resp.text(); } @@ -11907,17 +11943,17 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr cb.className = 'md-history-pick'; cb.addEventListener('change', function () { if (cb.checked) { - selected.push(ent.sha); + selected.push(ent.id); // Keep at most two: drop the oldest selection. if (selected.length > 2) { var dropped = selected.shift(); var others = list.querySelectorAll('.md-history-pick'); others.forEach(function (o, i) { - if (o !== cb && entries[i] && entries[i].sha === dropped) o.checked = false; + if (o !== cb && entries[i] && entries[i].id === dropped) o.checked = false; }); } } else { - selected = selected.filter(function (s) { return s !== ent.sha; }); + selected = selected.filter(function (s) { return s !== ent.id; }); } syncDiffBtn(); }); @@ -11956,7 +11992,7 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr if (selected.length !== 2) return; // Order oldest→newest by the entries' position (newest // first in the list), so the diff reads old → new. - var picks = entries.filter(function (e) { return selected.indexOf(e.sha) !== -1; }); + var picks = entries.filter(function (e) { return selected.indexOf(e.id) !== -1; }); picks.sort(function (a, b) { return (a.ts < b.ts ? -1 : 1); }); renderDiff(modal, node, picks[0], picks[1], entries); } @@ -11973,7 +12009,7 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr body.innerHTML = '

Loading…

'; var text; try { - text = await fetchVersion(node, ent.sha); + text = await fetchVersion(node, ent.id); } catch (e) { body.innerHTML = ''; var err = document.createElement('p'); @@ -12010,8 +12046,8 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr body.innerHTML = '

Loading…

'; var oldText, newText; try { - oldText = await fetchVersion(node, oldEnt.sha); - newText = await fetchVersion(node, newEnt.sha); + oldText = await fetchVersion(node, oldEnt.id); + newText = await fetchVersion(node, newEnt.id); } catch (e) { body.innerHTML = ''; var err = document.createElement('p'); @@ -12083,7 +12119,7 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr return; } try { - var text = await fetchVersion(node, ent.sha); + var text = await fetchVersion(node, ent.id); var resp = await fetch(node.url, { method: 'PUT', credentials: 'same-origin', diff --git a/zddc/internal/apps/embedded/classifier.html b/zddc/internal/apps/embedded/classifier.html index f4ffd63..d45f403 100644 --- a/zddc/internal/apps/embedded/classifier.html +++ b/zddc/internal/apps/embedded/classifier.html @@ -1793,7 +1793,7 @@ body.is-elevated::after {
ZDDC Classifier - v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85 + v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4
@@ -9864,23 +9864,26 @@ X.B(E,Y);return E}return J}()) } }()); -// shared/elevation.js — admin elevation toggle. +// shared/elevation.js — admin elevation via URL toggle. // -// Sudo-style model: admins behave as normal users by default; clicking -// the header toggle elevates the session so admin escape hatches (WORM -// bypass, .zddc edit authority, profile admin scaffolds) start firing. -// State is carried in a `zddc-elevate=1` cookie that the server reads -// via handler.ACLMiddleware → zddc.Principal{Elevated}. +// Sudo-style model: admins behave as normal users by default; elevating +// the session turns on admin escape hatches (WORM bypass, .zddc edit +// authority, profile admin scaffolds). State is carried in a +// `zddc-elevate=1` cookie that the server reads via handler.ACLMiddleware +// → zddc.Principal{Elevated}. // -// Only renders the toggle when /.profile/access reports the caller has -// some admin scope — a non-admin sees nothing, which keeps the chrome -// quiet for the common case. The toggle fades in once access loads so -// non-admins never even see the affordance flash. +// Toggle is by URL query param — `?admin=true` to arm, `?admin=false` +// (or the red banner's "Drop admin" button) to drop — so it's reachable +// from ANY zddc-server page, not just ones that render a header control. +// The cookie is the sticky state: it persists across navigation for its +// Max-Age window, so the param need not stay in the URL (we strip it). +// Arming is gated on /.profile/access `can_elevate`, so only real admins +// can set it; a non-admin's ?admin=true is a silent no-op. // -// Click flow: set/clear the cookie, then reload the page so the server -// sees the new state on the next render. The reload is intentional — -// admin scaffolds in tool HTML are server-rendered for some tools, so -// a soft state flip on the client alone wouldn't reach those. +// Applying the cookie reloads to the cleaned URL so the server re-renders +// under the new state (admin scaffolds in some tool HTML are server- +// rendered, so a client-only flip wouldn't reach them). The red viewport +// border + banner (applyArmedChrome) reflect the cookie on every load. (function () { 'use strict'; @@ -9925,22 +9928,65 @@ X.B(E,Y);return E}return J}()) } } - function render(host, elevated) { - host.classList.remove('hidden'); - host.innerHTML = - '' - + ''; - var cb = host.querySelector('#elevation-checkbox'); - cb.addEventListener('change', function () { - setElevated(cb.checked); - // Hard reload so server-rendered admin surfaces (profile - // page scaffolds, hidden-entry listings) catch up. URL - // and scroll state are preserved by the browser's normal - // back-forward cache rules. - window.location.reload(); - }); + // ── URL toggle: ?admin=true | ?admin=false (typeable anywhere) ────── + // + // Admin mode is toggled via a URL query param rather than an on-screen + // checkbox, so it's reachable from any zddc-server page. The param only + // SETS the cookie; the cookie is the sticky state (it persists across + // navigation for its Max-Age window and is what the server reads), so + // there's no need to keep ?admin= in the URL once applied. + + // adminParam returns true/false for a recognised ?admin= value, or null + // when absent / unrecognised (ignored). + function adminParam() { + try { + var v = new URLSearchParams(window.location.search).get('admin'); + if (v === null) return null; + v = v.toLowerCase(); + if (v === 'true' || v === '1' || v === 'on' || v === 'yes') return true; + if (v === 'false' || v === '0' || v === 'off' || v === 'no') return false; + return null; + } catch (_e) { return null; } + } + + // urlWithoutAdmin returns the current URL with the admin param stripped + // (other params + hash preserved) — what we navigate/replace to so the + // dirty param isn't bookmarked and Back doesn't re-trigger it. + function urlWithoutAdmin() { + var u = new URL(window.location.href); + u.searchParams.delete('admin'); + var qs = u.searchParams.toString(); + return u.pathname + (qs ? '?' + qs : '') + u.hash; + } + + // handleAdminParam applies a ?admin= request. Returns true when a + // navigation (reload) is underway so the caller can stop. Enabling is + // gated on can_elevate — a non-admin who types ?admin=true just gets + // the param stripped, never a misleading red border. Disabling is open + // (anyone may drop a cookie they somehow hold). + async function handleAdminParam() { + var want = adminParam(); + if (want === null) return false; + var clean = urlWithoutAdmin(); + if (want === isElevated()) { + // Already in the requested state — just clean the URL, no reload. + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + if (want === true) { + var access = await fetchAccess(); + if (!access || !access.can_elevate) { + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + setElevated(true); + } else { + setElevated(false); + } + // Navigate to the clean URL (a real load, so the server re-renders + // under the new cookie) and replace history so Back is safe. + window.location.replace(clean); + return true; } // Page-wide affordances when elevation is active. The toggle alone @@ -9982,26 +10028,16 @@ X.B(E,Y);return E}return J}()) } async function init() { - // Body chrome applies on every page load whether or not the - // header has a toggle slot — the banner needs to surface in - // tools / pages that don't host the toggle (e.g. iframed - // classifier inside browse's grid mode), so the user can't - // accidentally write through an elevated context elsewhere. + // Apply (or tear down) the red border + banner from the cookie on + // every page load — admin mode is toggled by URL, but the armed + // chrome must surface everywhere so the user can't accidentally + // write through an elevated context on a page they didn't toggle. applyArmedChrome(isElevated()); - var host = document.getElementById('elevation-toggle'); - if (!host) return; // tool doesn't include the slot yet — no-op - var access = await fetchAccess(); - if (!access) return; // anonymous / endpoint missing — no-op - // Surface ONLY for users who have admin authority somewhere. - // /.profile/access ships `can_elevate` as an elevation- - // INDEPENDENT signal — true for any user named in any admin - // list, regardless of current cookie state. The other flags - // (is_super_admin, has_any_admin_scope) reflect EFFECTIVE - // authority and would be false for an un-elevated admin - // who hasn't toggled yet — so we can't gate on those. - if (!access.can_elevate) return; - render(host, isElevated()); + // Honour ?admin=true|false typed into any zddc-server URL. There's + // no on-screen toggle anymore — the URL is the enable path and the + // red banner's "Drop admin" button is the one-click disable. + await handleAdminParam(); } if (document.readyState === 'loading') { diff --git a/zddc/internal/apps/embedded/index.html b/zddc/internal/apps/embedded/index.html index 831e6ff..121f8df 100644 --- a/zddc/internal/apps/embedded/index.html +++ b/zddc/internal/apps/embedded/index.html @@ -1536,7 +1536,7 @@ body {
ZDDC - v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85 + v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4
@@ -2546,23 +2546,26 @@ body { } }()); -// shared/elevation.js — admin elevation toggle. +// shared/elevation.js — admin elevation via URL toggle. // -// Sudo-style model: admins behave as normal users by default; clicking -// the header toggle elevates the session so admin escape hatches (WORM -// bypass, .zddc edit authority, profile admin scaffolds) start firing. -// State is carried in a `zddc-elevate=1` cookie that the server reads -// via handler.ACLMiddleware → zddc.Principal{Elevated}. +// Sudo-style model: admins behave as normal users by default; elevating +// the session turns on admin escape hatches (WORM bypass, .zddc edit +// authority, profile admin scaffolds). State is carried in a +// `zddc-elevate=1` cookie that the server reads via handler.ACLMiddleware +// → zddc.Principal{Elevated}. // -// Only renders the toggle when /.profile/access reports the caller has -// some admin scope — a non-admin sees nothing, which keeps the chrome -// quiet for the common case. The toggle fades in once access loads so -// non-admins never even see the affordance flash. +// Toggle is by URL query param — `?admin=true` to arm, `?admin=false` +// (or the red banner's "Drop admin" button) to drop — so it's reachable +// from ANY zddc-server page, not just ones that render a header control. +// The cookie is the sticky state: it persists across navigation for its +// Max-Age window, so the param need not stay in the URL (we strip it). +// Arming is gated on /.profile/access `can_elevate`, so only real admins +// can set it; a non-admin's ?admin=true is a silent no-op. // -// Click flow: set/clear the cookie, then reload the page so the server -// sees the new state on the next render. The reload is intentional — -// admin scaffolds in tool HTML are server-rendered for some tools, so -// a soft state flip on the client alone wouldn't reach those. +// Applying the cookie reloads to the cleaned URL so the server re-renders +// under the new state (admin scaffolds in some tool HTML are server- +// rendered, so a client-only flip wouldn't reach them). The red viewport +// border + banner (applyArmedChrome) reflect the cookie on every load. (function () { 'use strict'; @@ -2607,22 +2610,65 @@ body { } } - function render(host, elevated) { - host.classList.remove('hidden'); - host.innerHTML = - '' - + ''; - var cb = host.querySelector('#elevation-checkbox'); - cb.addEventListener('change', function () { - setElevated(cb.checked); - // Hard reload so server-rendered admin surfaces (profile - // page scaffolds, hidden-entry listings) catch up. URL - // and scroll state are preserved by the browser's normal - // back-forward cache rules. - window.location.reload(); - }); + // ── URL toggle: ?admin=true | ?admin=false (typeable anywhere) ────── + // + // Admin mode is toggled via a URL query param rather than an on-screen + // checkbox, so it's reachable from any zddc-server page. The param only + // SETS the cookie; the cookie is the sticky state (it persists across + // navigation for its Max-Age window and is what the server reads), so + // there's no need to keep ?admin= in the URL once applied. + + // adminParam returns true/false for a recognised ?admin= value, or null + // when absent / unrecognised (ignored). + function adminParam() { + try { + var v = new URLSearchParams(window.location.search).get('admin'); + if (v === null) return null; + v = v.toLowerCase(); + if (v === 'true' || v === '1' || v === 'on' || v === 'yes') return true; + if (v === 'false' || v === '0' || v === 'off' || v === 'no') return false; + return null; + } catch (_e) { return null; } + } + + // urlWithoutAdmin returns the current URL with the admin param stripped + // (other params + hash preserved) — what we navigate/replace to so the + // dirty param isn't bookmarked and Back doesn't re-trigger it. + function urlWithoutAdmin() { + var u = new URL(window.location.href); + u.searchParams.delete('admin'); + var qs = u.searchParams.toString(); + return u.pathname + (qs ? '?' + qs : '') + u.hash; + } + + // handleAdminParam applies a ?admin= request. Returns true when a + // navigation (reload) is underway so the caller can stop. Enabling is + // gated on can_elevate — a non-admin who types ?admin=true just gets + // the param stripped, never a misleading red border. Disabling is open + // (anyone may drop a cookie they somehow hold). + async function handleAdminParam() { + var want = adminParam(); + if (want === null) return false; + var clean = urlWithoutAdmin(); + if (want === isElevated()) { + // Already in the requested state — just clean the URL, no reload. + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + if (want === true) { + var access = await fetchAccess(); + if (!access || !access.can_elevate) { + try { history.replaceState(history.state, '', clean); } catch (_e) {} + return false; + } + setElevated(true); + } else { + setElevated(false); + } + // Navigate to the clean URL (a real load, so the server re-renders + // under the new cookie) and replace history so Back is safe. + window.location.replace(clean); + return true; } // Page-wide affordances when elevation is active. The toggle alone @@ -2664,26 +2710,16 @@ body { } async function init() { - // Body chrome applies on every page load whether or not the - // header has a toggle slot — the banner needs to surface in - // tools / pages that don't host the toggle (e.g. iframed - // classifier inside browse's grid mode), so the user can't - // accidentally write through an elevated context elsewhere. + // Apply (or tear down) the red border + banner from the cookie on + // every page load — admin mode is toggled by URL, but the armed + // chrome must surface everywhere so the user can't accidentally + // write through an elevated context on a page they didn't toggle. applyArmedChrome(isElevated()); - var host = document.getElementById('elevation-toggle'); - if (!host) return; // tool doesn't include the slot yet — no-op - var access = await fetchAccess(); - if (!access) return; // anonymous / endpoint missing — no-op - // Surface ONLY for users who have admin authority somewhere. - // /.profile/access ships `can_elevate` as an elevation- - // INDEPENDENT signal — true for any user named in any admin - // list, regardless of current cookie state. The other flags - // (is_super_admin, has_any_admin_scope) reflect EFFECTIVE - // authority and would be false for an un-elevated admin - // who hasn't toggled yet — so we can't gate on those. - if (!access.can_elevate) return; - render(host, isElevated()); + // Honour ?admin=true|false typed into any zddc-server URL. There's + // no on-screen toggle anymore — the URL is the enable path and the + // red banner's "Drop admin" button is the one-click disable. + await handleAdminParam(); } if (document.readyState === 'loading') { diff --git a/zddc/internal/apps/embedded/transmittal.html b/zddc/internal/apps/embedded/transmittal.html index 756a834..8a4672e 100644 --- a/zddc/internal/apps/embedded/transmittal.html +++ b/zddc/internal/apps/embedded/transmittal.html @@ -2635,7 +2635,7 @@ dialog.modal--narrow {
ZDDC Transmittal - v0.0.27-beta · 2026-06-01 18:30:53 · 5ed4f85 + v0.0.27-beta · 2026-06-02 19:01:22 · af07fa4
JavaScript not available