Accounts and sign-in, and fix the read toggle
epAction's redraw closure called itself when handed a row, so Mark read recursed until the stack blew; it now swaps that row in place. Opening an item also marks it read, redrawn where it stands so nothing vanishes from under the pointer on the Unread tab. Step A of multi-user: users and sessions tables, Argon2id, a session cookie, ipx user subcommands, and a trusted proxy header for Cloudflare Zero Trust -- honoured only from a trusted_proxies address. The shared token still works and is the admin. A new database starts with admin/ipodderx. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
46
PROGRESS.md
46
PROGRESS.md
@@ -56,19 +56,55 @@ and until now nothing set them.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-10 — Marking an item read
|
||||
|
||||
Two bugs in one place. `epAction`'s `redraw` closure called *itself* when it had a row to
|
||||
update -- `if(el) redraw()` where it meant to swap the row -- so the Mark read button in the
|
||||
text pane recursed until the stack blew. It now swaps that one row in place and refreshes the
|
||||
text below only when it is the item being read.
|
||||
|
||||
And opening an item now marks it read, which is what clicking a thing to read it means. The row
|
||||
is redrawn where it stands rather than the list reloaded, so an item does not vanish from under
|
||||
the pointer on the Unread tab.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-10 — Step A: accounts and sign-in
|
||||
|
||||
`users` and `sessions` tables, Argon2id hashing, a session cookie, and `ipx user add|list|passwd|rm`
|
||||
(passwords come in on stdin, so they miss the shell history and any `ps` listing).
|
||||
|
||||
Three ways in, in order of how specific the claim is:
|
||||
|
||||
1. **A proxy header** naming the user -- `Cf-Access-Authenticated-User-Email` for the Cloudflare
|
||||
Zero Trust in front of `ipodderx.sdf1.net`. Honoured **only** from an address in
|
||||
`trusted_proxies` (loopback by default): a header is worth exactly as much as the hop that set
|
||||
it, and the LAN port would otherwise let anyone claim to be anyone. Verified both ways -- a
|
||||
spoof from an untrusted address is refused.
|
||||
2. **A session cookie** from signing in at `/login`.
|
||||
3. **The shared token**, which is the admin, so the healthcheck and existing links keep working.
|
||||
|
||||
A database with no accounts creates **admin / ipodderx** and says so loudly in the log. The UI shows
|
||||
who is signed in above the sidebar footer, with a sign-out, and a 401 sends the page to `/login`.
|
||||
|
||||
Nothing is per-user *yet*: everyone still sees the same feeds and read state. That is step B.
|
||||
|
||||
---
|
||||
|
||||
## Multi-user — the plan
|
||||
|
||||
Decided with Ray: **stay on SQLite** (Postgres was considered and dropped -- it is a deployment
|
||||
choice, not a capability one, and nothing here contends for writes). Sign-in is either a local
|
||||
username and password or the Authentik that already fronts `ipodderx.sdf1.net` through a Cloudflare
|
||||
tunnel. Feeds, items and files are **shared**; read state and subscriptions are **per user**.
|
||||
username and password or the Cloudflare Zero Trust that already fronts `ipodderx.sdf1.net`, which
|
||||
puts the authenticated identity in `Cf-Access-Authenticated-User-Email`. Feeds, items and files are **shared**; read state and subscriptions are **per user**.
|
||||
|
||||
The point of sharing: two people subscribed to the same show cost one fetch, one parse, and one file
|
||||
on disk. `enclosures.url` is already globally UNIQUE, so the file half is nearly free.
|
||||
|
||||
- [ ] **A. Users, sessions, sign-in.** `users` + `sessions` tables, Argon2 hashing, session cookie,
|
||||
`ipx user add|list|passwd|rm`. Authentik/proxy header (`trusted_header` in `[web]`) signs in and
|
||||
optionally creates a user. The existing shared token keeps working and resolves to the admin, so
|
||||
- [x] **A. Users, sessions, sign-in.** `users` + `sessions` tables, Argon2 hashing, session cookie,
|
||||
`ipx user add|list|passwd|rm`. A proxy header (`trusted_header` in `[web]`) signs in and
|
||||
optionally creates a user -- honoured only from a `trusted_proxies` address, so a LAN client
|
||||
cannot simply assert it. The existing shared token keeps working and resolves to the admin, so
|
||||
the healthcheck and any scripts survive. Login page for direct access.
|
||||
- [ ] **B. Per-user read state.** `entry_state(user_id, feed_id, guid, read, flagged, position)`;
|
||||
the current columns on `entries` migrate into the first user's rows. Unread counts, filters and
|
||||
|
||||
Reference in New Issue
Block a user