using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using Microsoft.Extensions.Hosting; namespace Jellyfin.Server.Implementations.Users; /// /// responsible for managing user device permissions. /// public sealed class DeviceAccessHost : IHostedService { private readonly IUserManager _userManager; private readonly IDeviceManager _deviceManager; private readonly ISessionManager _sessionManager; /// /// Initializes a new instance of the class. /// /// The . /// The . /// The . public DeviceAccessHost(IUserManager userManager, IDeviceManager deviceManager, ISessionManager sessionManager) { _userManager = userManager; _deviceManager = deviceManager; _sessionManager = sessionManager; } /// public Task StartAsync(CancellationToken cancellationToken) { _userManager.OnUserUpdated += OnUserUpdated; return Task.CompletedTask; } /// public Task StopAsync(CancellationToken cancellationToken) { _userManager.OnUserUpdated -= OnUserUpdated; return Task.CompletedTask; } private async void OnUserUpdated(object? sender, GenericEventArgs e) { var user = e.Argument; if (!user.HasPermission(PermissionKind.EnableAllDevices)) { await UpdateDeviceAccess(user).ConfigureAwait(false); } } private async Task UpdateDeviceAccess(User user) { var existing = (await _deviceManager.GetDevices(new DeviceQuery { UserId = user.Id }).ConfigureAwait(false)).Items; foreach (var device in existing) { if (!string.IsNullOrEmpty(device.DeviceId) && !_deviceManager.CanAccessDevice(user, device.DeviceId)) { await _sessionManager.Logout(device).ConfigureAwait(false); } } } }