Commit graph

1 commit

Author SHA1 Message Date
00b20550c2 Accounts are owner-created, and one page manages the whole account
Registration is closed. The instance was gated by a single shared invite code in
AMBER_INVITE_CODE -- a bearer secret, one string for everyone, forever, no record
of who used it, and known to every family member who ever onboarded, so it leaked
by design. An email whitelist was the obvious replacement and does not survive
contact with the facts: it binds to a person only if the address is verified, and
all five accounts on this instance are `verified = false`. For a household this
size the owner creating each account in the admin UI is stronger than either and
has nothing to leak. `users.createRule` is superuser-only now, and the hook
refuses with a sentence a family member can read rather than a bare 403.

The family code survives with a narrower job. It is no longer a key to the front
door; it is what unlocks the *shared family credentials* during setup. Close
friends get accounts too and bring their own (BYOC), so "has an account" must not
mean "may have the family's sources" -- the template route now wants auth AND the
code, keeping its rate limiter because the code is still a shared secret.

pb_public/account.html replaces index/settings/onboarding with one page behind a
persisted session: profiles (name, child flag, age ceiling, PIN), the 13 synced
playback preferences per profile, sources, devices, downloads, account. The token
persists in localStorage; the password never does, and anything needing it asks in
the moment -- that is the honest split between "stay signed in" and "hold the key
to your credentials in a browser tab".

Sources can now be set up from your own service credentials. The page posts them
straight to the addon's own /encode and builds TorBox's config token locally --
both addons send permissive CORS, so the credentials go from the family member's
browser to the addon and never touch our server. prehraj.to is required because
the addon's /encode returns 400 without it and decodeConfig rejects such a token,
so "webshare only" is not currently possible; the copy says so rather than
pretending. TorBox is optional and the copy is emphatic about what it is for.

Two hazards handled rather than hoped over. Changing the password re-keys the
addon vault, and the re-encrypt happens BEFORE the password PATCH: if it were
after, a failure would leave a blob no device can read. And prefs writes carry
`updatedAt`, the clock the app's LWW actually compares -- the server's `updated`
is only the pull cursor -- and merge into the existing data rather than replacing
it, because the app writes fields this page does not show yet.

Also: `users.ratingDefault`, so the account-wide age ceiling stops being the one
half of a parental control that does not sync. The app side ships with the next
release. The other three device-local settings stay local on purpose, and
`adult_enabled` most deliberately of all.

Plan and reasoning: docs/plan-accounts-and-web.md in amber-app.
2026-08-07 01:54:25 +02:00