store the token provisioning mints, so members can open video
Provisioning already created each member's Jellyfin account and signed in as them to get a token — its own header says the token exists so "the person's Officer session can already read their library". It was then dropped, because linkJellyfinAccount had nowhere to put it. So every non-owner resolved to no config and got a 503 setup form, asking them to connect a Jellyfin server with a password nobody knows. It reads as a permissions fault and is not one: the grant, the role and the account list were all correct. jellyfin_accounts now carries access_token and device_id, getConfig falls back to the link row when the caller has no registry of their own, and there is no path from there to the owner's token — a member resolving to the owner's credential would read the owner's watch state and every library. POST /_config/:id/provision repairs accounts linked before the column existed. It resets the password to mint, which is free on an account Officer created (random, discarded, known to nobody) and destructive on an adopted one, so adopted accounts are skipped unless includeAdopted says otherwise. Applied on alpha: conceiba and guipinto minted and verified against the live server; fedra and diogo skipped as adopted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,29 @@ export const jellyfinAccounts = pgTable(
|
||||
normalizedUsername: text('normalized_username').notNull(),
|
||||
/** False = Officer created it and may remove it. True = it pre-existed and was linked. */
|
||||
adopted: boolean('adopted').notNull().default(false),
|
||||
/**
|
||||
* That person's OWN Jellyfin access token, encrypted — the credential their Officer session reads the
|
||||
* library with.
|
||||
*
|
||||
* This column is the whole point of the per-user design and it was missing until 2026-08-21.
|
||||
* `provision.ts` already minted exactly this token, said in its own header that it exists so "the
|
||||
* person's Officer session can already read their library", and then dropped it on the floor because
|
||||
* `linkJellyfinAccount` had nowhere to put it. Every non-owner therefore resolved to no config and got
|
||||
* a 503 setup form, while the owner worked — which reads as a permissions fault and is not one.
|
||||
*
|
||||
* NULLABLE, and the null case is normal rather than an error: a token can only be obtained by signing
|
||||
* in, so an ADOPTED account has none until somebody supplies its password. An Officer-created account
|
||||
* always has one, because provisioning knows the password it just set.
|
||||
*/
|
||||
accessToken: text('access_token'), // encrypted
|
||||
/**
|
||||
* The DeviceId this person's sessions are keyed by, `officer-<officer user id>`.
|
||||
*
|
||||
* Written with the token and meaningless without it. Distinct from the owner's device id on purpose —
|
||||
* Jellyfin lists them separately under Devices, so revoking one person's access does not sign
|
||||
* everybody else out.
|
||||
*/
|
||||
deviceId: text('device_id'),
|
||||
linkedAt: timestamp('linked_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
},
|
||||
(table) => [
|
||||
|
||||
Reference in New Issue
Block a user