password reset: an admin makes a one-hour link, and using it signs the account out everywhere
CI & Build / Python lint (push) Successful in 3s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Android / Kotlin + Rust (APK) (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Failing after 12s
CI & Build / integration (push) Successful in 49s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 1m41s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m4s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m5s
Desktop (Tauri) / Update manifest (push) Successful in 5s

There is no mail path, so a forgotten password needed a hand on the database
(#2939 §2). Settings → People lists the accounts; Reset password makes a link
that works once within an hour, shown once for the admin to hand over. Making
another link for the same account closes the earlier one.

Using it (/reset-password) sets the password, deletes the account's device
tokens, and moves users.session_epoch on. Sessions are signed cookies the
server can't delete, so each now carries the epoch it signed in under and
login_required reads the account's epoch by primary key. A cookie from before
this has no epoch and reads as 0, the starting value, so the upgrade signs
nobody out. A deleted account's session now stops working too.

The one-time link reveal moves out of InviteList into OneTimeLink, and the
link-building into router/links.ts, shared by invites and resets.

Migration 0033. #5173.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 14:35:58 -04:00
co-authored by Claude Opus 5.5
parent 28fa8badcb
commit 3dd0b44cb9
17 changed files with 696 additions and 61 deletions
+5 -2
View File
@@ -112,8 +112,11 @@ docker run --rm -v inkwell-data:/d -v "$PWD":/out alpine tar czf /out/media.tgz
Know these before you decide who gets an account.
- **No email verification and no password reset.** `email_verified` exists on the user
row and nothing sets it. A forgotten password needs a hand on the database.
- **No email at all.** `email_verified` exists on the user row and nothing sets it.
A forgotten password is reset by an admin: Settings → People → Reset password makes
a link that works once, within an hour, and the admin hands it over. Using it signs
the account out everywhere and unlinks its apps. An admin who forgets their own
password and has no other admin still needs a hand on the database.
- **No second factor.** A password is the whole of it.
- **No per-user storage quota.** Any account can upload attachments until the volume
is full. `max_attachment_mb` caps a single file, not a total.