Allow non-admin users to subscribe to their own Sessions (#13767)

This commit is contained in:
KGT1
2025-09-12 22:15:00 +02:00
committed by GitHub
parent 96590eea85
commit 7c6cedd90a
2 changed files with 38 additions and 12 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data; using Jellyfin.Data;
using Jellyfin.Database.Implementations.Enums; using Jellyfin.Database.Implementations.Enums;
@@ -56,6 +57,21 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume
return Task.FromResult(_sessionManager.Sessions); return Task.FromResult(_sessionManager.Sessions);
} }
/// <inheritdoc />
protected override Task<IEnumerable<SessionInfo>> GetDataToSendForConnection(IWebSocketConnection connection)
{
// For non-admin users, filter the sessions to only include their own sessions
if (connection.AuthorizationInfo?.User is not null &&
!connection.AuthorizationInfo.IsApiKey &&
!connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator))
{
var userId = connection.AuthorizationInfo.User.Id;
return Task.FromResult(_sessionManager.Sessions.Where(s => s.UserId.Equals(userId) || s.ContainsUser(userId)));
}
return Task.FromResult(_sessionManager.Sessions);
}
/// <inheritdoc /> /// <inheritdoc />
protected override async ValueTask DisposeAsyncCore() protected override async ValueTask DisposeAsyncCore()
{ {
@@ -80,11 +96,10 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume
/// <param name="message">The message.</param> /// <param name="message">The message.</param>
protected override void Start(WebSocketMessageInfo message) protected override void Start(WebSocketMessageInfo message)
{ {
if (!message.Connection.AuthorizationInfo.IsApiKey // Allow all authenticated users to subscribe to session information
&& (message.Connection.AuthorizationInfo.User is null if (message.Connection.AuthorizationInfo.User is null && !message.Connection.AuthorizationInfo.IsApiKey)
|| !message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)))
{ {
throw new AuthenticationException("Only admin users can subscribe to session information."); throw new AuthenticationException("User must be authenticated to subscribe to session Information.");
} }
base.Start(message); base.Start(message);

View File

@@ -80,6 +80,16 @@ namespace MediaBrowser.Controller.Net
/// <returns>Task{`1}.</returns> /// <returns>Task{`1}.</returns>
protected abstract Task<TReturnDataType> GetDataToSend(); protected abstract Task<TReturnDataType> GetDataToSend();
/// <summary>
/// Gets the data to send for a specific connection.
/// </summary>
/// <param name="connection">The connection.</param>
/// <returns>Task{`1}.</returns>
protected virtual Task<TReturnDataType> GetDataToSendForConnection(IWebSocketConnection connection)
{
return GetDataToSend();
}
/// <summary> /// <summary>
/// Processes the message. /// Processes the message.
/// </summary> /// </summary>
@@ -174,17 +184,11 @@ namespace MediaBrowser.Controller.Net
continue; continue;
} }
var data = await GetDataToSend().ConfigureAwait(false);
if (data is null)
{
continue;
}
IEnumerable<Task> GetTasks() IEnumerable<Task> GetTasks()
{ {
foreach (var tuple in tuples) foreach (var tuple in tuples)
{ {
yield return SendDataInternal(data, tuple); yield return SendDataForConnectionAsync(tuple);
} }
} }
@@ -198,12 +202,19 @@ namespace MediaBrowser.Controller.Net
} }
} }
private async Task SendDataInternal(TReturnDataType data, (IWebSocketConnection Connection, CancellationTokenSource CancellationTokenSource, TStateType State) tuple) private async Task SendDataForConnectionAsync((IWebSocketConnection Connection, CancellationTokenSource CancellationTokenSource, TStateType State) tuple)
{ {
try try
{ {
var (connection, cts, state) = tuple; var (connection, cts, state) = tuple;
var cancellationToken = cts.Token; var cancellationToken = cts.Token;
var data = await GetDataToSendForConnection(connection).ConfigureAwait(false);
if (data is null)
{
return;
}
await connection.SendAsync( await connection.SendAsync(
new OutboundWebSocketMessage<TReturnDataType> { MessageType = Type, Data = data }, new OutboundWebSocketMessage<TReturnDataType> { MessageType = Type, Data = data },
cancellationToken).ConfigureAwait(false); cancellationToken).ConfigureAwait(false);