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.
38 lines
1.8 KiB
C#
38 lines
1.8 KiB
C#
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using MediaBrowser.Model.Plugins;
|
|
|
|
namespace Jellyfin.Plugin.WatchedTogether.Configuration;
|
|
|
|
/// <summary>
|
|
/// Plugin configuration. Holds the authoritative record of which members belong to which
|
|
/// shared account.
|
|
/// </summary>
|
|
public class PluginConfiguration : BasePluginConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the configured shared-account groups.
|
|
/// </summary>
|
|
[SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Plugin configuration is round-tripped by the XML serializer, which requires a settable List<T>.")]
|
|
[SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "Plugin configuration is round-tripped by the XML serializer, which requires a settable List<T>.")]
|
|
public List<SharedGroup> Groups { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Gets or sets the separator used to join member names into a shared account name. Also the
|
|
/// separator split at login when <see cref="EnableDynamicGroups"/> is on.
|
|
/// </summary>
|
|
public string NameSeparator { get; set; } = "+";
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether typing an unrecognised name like "alice+bob" at the
|
|
/// login screen creates the shared account on the spot.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The account is only created if every named part is an existing, enabled, non-shared user
|
|
/// <em>and</em> the submitted password belongs to one of them. A real account whose name
|
|
/// happens to contain the separator always takes precedence, because Jellyfin only consults
|
|
/// this plugin once no local user matches the typed name.
|
|
/// </remarks>
|
|
public bool EnableDynamicGroups { get; set; } = true;
|
|
}
|