Settings → Activity: an audit log of what happened to accounts
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 / Core and FFI clippy and tests (push) Skipped
Android / Kotlin + Rust (APK) (push) Skipped
Android / Build the server image (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 10s
CI & Build / Python tests (push) Successful in 14s
CI & Build / integration (push) Successful in 1m27s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 1m47s
CI & Build / Build & push image (push) Successful in 45s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m24s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m4s
Desktop (Tauri) / Update manifest (push) Successful in 4s

Sign-ins and failed sign-ins, accounts created and sign-ups refused,
password changes, resets and reset links, devices linked and unlinked,
invites made and revoked. Each is kept in `audit_events` with the address
it came from, for `audit_retention_days` (Settings → Security, 90 by
default, 0 keeps them forever), and listed newest first for admins under
Settings → Activity. The retention loop deletes older events.

`audit.record` writes in its own session, so a refusal is kept even when
the request's transaction rolls back. A failure to record is logged and
swallowed, never the reason a sign-in fails. A throttled attempt (429) is
not recorded: a row per refused request would make each request in a
flood cost a database write. Throttle trips stay in the app log.

Also: the storage-limit test puts `storage_quota_gb` back afterwards,
since settings outlive the per-test truncate.

#2939 §5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 11:19:41 -04:00
co-authored by Claude Opus 5.5
parent 043c87a8dc
commit 39b1ebae96
14 changed files with 509 additions and 21 deletions
+19 -6
View File
@@ -4,7 +4,7 @@ Inkwell is built to run on a LAN and works fine there with no ceremony. Exposing
it changes the threat model: anyone can now reach the login form, and any account is
one guessed password away from someone's whole note history.
This is what the app does about that on its own, and the four things it cannot do for
This is what the app does about that on its own, and the three things it cannot do for
you.
## Do these five things first
@@ -154,6 +154,24 @@ page shows how much an account uses.
`max_attachment_mb` still caps any single file.
## Activity
**Settings → Activity** lists what has happened to accounts, newest first, with the
address each came from:
- sign-ins and failed sign-ins;
- accounts created and sign-ups refused;
- password changes, resets and reset links;
- devices linked and unlinked;
- invites made and revoked.
Events are kept for `audit_retention_days` (Settings → Security, 90 by default; 0
keeps them forever). Admins only.
A throttled attempt (429) is not listed, so that a flood of them costs no database
writes. Throttle trips are in the app log, with every event above:
`docker compose logs app`.
## What it does not do
Know these before you decide who gets an account.
@@ -165,11 +183,6 @@ Know these before you decide who gets an account.
- **An admin who forgets their own password**, with email off and no other admin,
still needs a hand on the database.
- **No second factor.** A password is the whole of it.
- **No audit TABLE.** Credential events — sign-ins, failures, throttle trips, new
accounts, device tokens issued — are written to the application log and readable
with `docker compose logs app`, which is enough to see whether anyone is knocking.
They are not queryable, not retained beyond the container's log rotation, and not
attributable after the fact.
None of these are hard blockers for an instance whose accounts are you and people you
know. They are the reason not to hand out open registration to strangers.