(opus assessment) Fix auth wall flash, broken multi-user write API, and single-user redirect loop

Auth wall (Base.astro): set data-auth-pending on <body> at SSG time and hide
  it with inline CSS before any JS runs; remove the attribute after /api/me
  resolves. Eliminates the flash of protected content on private instances.

  Multi-user write API (serve/server.py): the previous _apply_sidecar_edit and
  strava_sync imports from bincio.edit.server were broken (those names don't
  exist as module-level exports) and the Strava sync mutated a global data_dir,
  making concurrent requests from different users racy. Fix: extract both
  operations into bincio/edit/ops.py as pure functions that take data_dir
  explicitly. Both edit/server.py and serve/server.py now import from there.

  Security: add rate limiting to POST /api/register (5 attempts / 15 min / IP,
  separate bucket from login). Add _check_id() activity ID validation to both
  GET and POST /api/activity/{id} in serve/server.py.

  Single-user mode: _write_root_manifest now forces instance.private=false when
  no instance.db exists, even if a previous run wrote true. Prevents the auth
  wall from firing and redirecting to /login/ when bincio serve isn't running.

  ActivityFeed: skip filterHandle when profileIndexUrl is set (per-user profile
  pages load the right shard directly; activities have no handle tag at that
  point, so the filter was producing an empty feed). Fix handle links to point
  to /u/{handle}/ instead of /{handle}/. Fix <a>-inside-<a> Svelte warning by
  converting the inner handle link to a <button>.
This commit is contained in:
Davide Scaini
2026-04-09 09:19:48 +02:00
parent 98c42dc443
commit cf7c71b8a3
6 changed files with 87 additions and 117 deletions
+13 -3
View File
@@ -52,12 +52,21 @@ try {
});
</script>
<!-- Auth wall: redirect to /login/ on private instances when not authenticated -->
<!-- Auth wall: redirect to /login/ on private instances when not authenticated.
body[data-auth-pending] is hidden by CSS (below) before the check resolves,
eliminating the flash of protected content. -->
{instancePrivate && !isPublicPage && (
<style is:inline>[data-auth-pending]{visibility:hidden}</style>
<script is:inline>
fetch('/api/me', { credentials: 'include' })
.then(r => { if (r.status === 401 || r.status === 404) window.location.replace('/login/'); })
.catch(() => {});
.then(r => {
if (r.status === 401 || r.status === 404) {
window.location.replace('/login/');
} else {
document.body.removeAttribute('data-auth-pending');
}
})
.catch(() => { document.body.removeAttribute('data-auth-pending'); });
</script>
)}
@@ -132,6 +141,7 @@ try {
<body
class="font-sans antialiased min-h-screen"
style="background-color: var(--bg-base); color: var(--text-primary)"
data-auth-pending={instancePrivate && !isPublicPage ? '' : undefined}
>
<nav
class="border-b border-zinc-800 sticky top-0 z-50 bg-zinc-950/90 backdrop-blur"