Prevent cross-address login lockouts (Refs #63)
CI / checks (push) Successful in 6m30s

This commit is contained in:
2026-10-17 10:55:28 -04:00
parent f3b9699317
commit 4501eba873
14 changed files with 922 additions and 61 deletions
+41 -8
View File
@@ -113,9 +113,22 @@ revocation every 15 seconds and then close.
Login and password changes for enabled Administrators and Super Viewers are exempt
from per-account and per-address rate limits, including existing exhausted windows.
Their attempts do not consume either limit. Other accounts and initial setup use
persistent 15-minute windows. Exemptions use the account's current database role;
password verification is still required. The database stores audit entries for login
Their attempts do not consume either limit. Other accounts use persistent
15-minute login windows of 10 attempts per username-and-address pair and 30 per
address across accounts. Attempts from one address do not exhaust another
address's allowance for the same username. Initial setup and password changes
retain their limits of 10 per account and 30 per address. Exemptions use the
account's current database role; password verification is still required.
A successful password login also sets a separate, HTTP-only login-device cookie
for 30 days. This cookie lets that browser skip its username-and-address limit,
while the password and shared address limit still apply. It does not sign you in,
and is independent of **Keep me signed in**. It survives ordinary sign-out;
password changes/resets, role changes, disabling an account, and revoking all of
its sessions invalidate its login-device cookies. Only token hashes are stored in
SQLite. Reusing a valid cookie does not extend its original expiry.
The database stores audit entries for login
results, account changes and successful management requests without recording
passwords, tokens or request bodies. Administrators and Super Viewers can review
recent entries in Users.
@@ -138,8 +151,10 @@ DB_PATH=./data/cherry.db node scripts/reset-admin.mjs admin
Replace `admin` with the existing administrator's username. The command prompts
without echoing the password, resets that enabled administrator only, revokes
their sessions and records the recovery. It does not expose a remote recovery
endpoint or accept passwords as command arguments.
their sessions and trusted login devices, clears their account-specific login and
password-change rate limits, and records the recovery. Other users' limits and
shared address limits remain intact. It does not expose a remote recovery endpoint
or accept passwords as command arguments.
## Agent and telemetry connections
@@ -181,9 +196,27 @@ JSON requests and multipart uploads. Do not configure a proxy to replace arbitra
incoming origins with your trusted origin. Machine endpoints use their own token
checks and do not require a browser Origin.
Use the adapter's real client-address configuration only with a trusted proxy
that strips spoofed forwarding headers; login throttling otherwise uses the direct
peer address. Forwarded host or user headers do not authenticate users.
Login throttling uses the address returned by SvelteKit's adapter. Without
`ADDRESS_HEADER`, this is the direct peer address, so users behind a reverse proxy
share the proxy's address limit. Compose passes `ADDRESS_HEADER` and `XFF_DEPTH`
from `.env` to the controller; direct Node deployments must set them in the
server's environment. For one trusted proxy that sets `X-Forwarded-For`, use:
```dotenv
ADDRESS_HEADER=x-forwarded-for
XFF_DEPTH=1
```
Recreate the Compose controller after changing these values with
`docker compose up -d`. For a proxy chain, set `XFF_DEPTH` to the number of trusted
proxies: the adapter selects that many positions from the right of the header.
For example, `client, proxy1` with two trusted proxies requires `XFF_DEPTH=2`.
The public-facing proxy must replace untrusted forwarding headers, and every
trusted hop must supply the expected address chain. Restrict direct access to
port 3000 so requests cannot bypass those proxies. Do not enable these settings
for an untrusted proxy or copy a depth that does not match your deployment.
See the [adapter's client-address settings](https://svelte.dev/docs/kit/adapter-node#Environment-variables-ADDRESS_HEADER-and-XFF_DEPTH).
Forwarded host or user headers do not authenticate users.
Local HTTP browser development requires `EC_AUTH_ALLOW_HTTP=true` and a loopback
hostname (`localhost`, `127.0.0.1` or `::1`). This uses a separate development