Grant shared accounts the intersection of member library access
Previously the shared account's libraries were chosen independently of its members, so a group could see a library that one of its members was blocked from - joining a group became a way to gain access. That was especially sharp with auto-created groups, where no admin is in the loop. A shared account is now granted exactly the libraries every member can already reach. If one member is blocked from a library, no group containing them can see it. The account is therefore always a subset of what each member could reach alone, which is what makes creating groups at the login screen safe to leave on by default. Details: - "Enable all folders" is expanded to concrete library ids before intersecting, since it cannot otherwise be compared with an explicit list. Shared accounts are always given an explicit list, never the all-folders permission, so newly added libraries do not silently widen an existing group. - Explicitly blocked folders are subtracted even for members who otherwise have access to everything. - Fails closed: an unresolvable member contributes no access rather than being treated as unrestricted. - Recomputed when membership changes, and re-applied to every group at startup so narrowing a member's own access narrows their groups. Drops the now-meaningless EnableAllFolders/EnabledFolders provisioning inputs and the DynamicGroupsEnableAllFolders setting. Adds 8 tests covering the intersection rules.
This commit is contained in:
@@ -43,6 +43,10 @@ watch alone on their phone, the series picks up where the group left off.
|
||||
The sync is **one-way**: shared account → members. What Alice watches privately is her business and
|
||||
never leaks into the shared account or onto Bob.
|
||||
|
||||
Library access is the **intersection** of the members', never the union: the group sees only what
|
||||
everyone in it could already see. Sharing an account is therefore never a way to reach a library you
|
||||
were not already allowed into.
|
||||
|
||||
```
|
||||
login as "alice+bob+carol"
|
||||
with any one member's password
|
||||
@@ -174,8 +178,7 @@ If you would rather provision groups explicitly — or you have turned auto-crea
|
||||
1. Go to **Dashboard → Plugins → Watched Together**.
|
||||
2. Under **Create a group**, select **two or more** members.
|
||||
3. Optionally give the account a name. Left blank, the member names are joined with `+`.
|
||||
4. Decide whether the account should see all libraries (see the security note below).
|
||||
5. Click **Create group**.
|
||||
4. Click **Create group**.
|
||||
|
||||
Either way, a new user appears in your user list and can be renamed like any other.
|
||||
|
||||
@@ -192,26 +195,27 @@ Either way, a new user appears in your user list and can be renamed like any oth
|
||||
| Setting | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| Create groups automatically at login | on | Enables the `alice+bob` login flow described above. Turn off to require dashboard provisioning. |
|
||||
| Auto-created accounts can access all libraries | on | Whether accounts made at the login screen start with full library access. Turn off to grant access deliberately. |
|
||||
| Name separator | `+` | The character joining member names, and the one split at login. Use `_` or `-` if you prefer. |
|
||||
|
||||
There is no library-access setting: a shared account always receives exactly the intersection of its
|
||||
members' access. See the security notes below.
|
||||
|
||||
---
|
||||
|
||||
## Security notes
|
||||
|
||||
Please read this before granting a shared account broad library access.
|
||||
How this plugin bounds what a shared account can reach.
|
||||
|
||||
- **Access is a union, and it is deliberate.** Any member's password opens the shared account, and
|
||||
that account sees whatever libraries *you* granted *it*, independent of each member's own
|
||||
restrictions. If a member is normally blocked from a library but the shared account is not, that
|
||||
member's password now reaches it. Set the shared account's library access accordingly.
|
||||
- **Auto-creation grants library access without an admin in the loop.** With both
|
||||
*Create groups automatically at login* and *Auto-created accounts can access all libraries* on,
|
||||
any user who knows a colleague's username can pair it with their own and reach a full-library
|
||||
account. That is a real privilege escalation if your libraries are not uniformly visible. It is
|
||||
still gated on a valid member password — nobody gets in without one — but if per-user library
|
||||
restrictions matter to you, turn off *Auto-created accounts can access all libraries* (or
|
||||
auto-creation entirely) and provision groups from the dashboard.
|
||||
- **Library access is an intersection, never a union.** A shared account is granted only the
|
||||
libraries that *every* member can already reach. If Alice is blocked from a library, no group
|
||||
containing Alice can see it — even if everyone else can. Joining a group can therefore never grant
|
||||
anyone access they did not already have, which is what makes auto-creation safe to leave on.
|
||||
Members with nothing in common produce an account that sees nothing.
|
||||
- **Blocked folders stay blocked.** An explicitly blocked library is subtracted even from a member
|
||||
who otherwise has "access to all libraries".
|
||||
- **The intersection is recomputed, not frozen.** It is recalculated whenever a group's membership
|
||||
changes, and re-applied to every group at server startup, so narrowing a member's own access
|
||||
narrows the groups they belong to.
|
||||
- **Disabled members are excluded.** A disabled Jellyfin user can no longer unlock the shared
|
||||
account, and no longer receives watched state.
|
||||
- **Shared accounts cannot be nested.** A shared account may not be a member of another group; this
|
||||
|
||||
Reference in New Issue
Block a user