From 72534f9d667f2457cbe96ea870d140528e366ba2 Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Fri, 25 Sep 2020 09:25:59 +0200 Subject: Use SessionMessageType for WebSocket messages --- .../Session/SessionManager.cs | 28 +++++++++++----------- .../Session/SessionWebSocketListener.cs | 3 ++- .../Session/WebSocketController.cs | 3 ++- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index e42d47853..df1b1e452 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1064,10 +1064,10 @@ namespace Emby.Server.Implementations.Session AssertCanControl(session, controllingSession); } - return SendMessageToSession(session, "GeneralCommand", command, cancellationToken); + return SendMessageToSession(session, SessionMessageType.GeneralCommand, command, cancellationToken); } - private static async Task SendMessageToSession(SessionInfo session, string name, T data, CancellationToken cancellationToken) + private static async Task SendMessageToSession(SessionInfo session, SessionMessageType name, T data, CancellationToken cancellationToken) { var controllers = session.SessionControllers; var messageId = Guid.NewGuid(); @@ -1078,7 +1078,7 @@ namespace Emby.Server.Implementations.Session } } - private static Task SendMessageToSessions(IEnumerable sessions, string name, T data, CancellationToken cancellationToken) + private static Task SendMessageToSessions(IEnumerable sessions, SessionMessageType name, T data, CancellationToken cancellationToken) { IEnumerable GetTasks() { @@ -1178,7 +1178,7 @@ namespace Emby.Server.Implementations.Session } } - await SendMessageToSession(session, "Play", command, cancellationToken).ConfigureAwait(false); + await SendMessageToSession(session, SessionMessageType.Play, command, cancellationToken).ConfigureAwait(false); } /// @@ -1186,7 +1186,7 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); - await SendMessageToSession(session, "SyncPlayCommand", command, cancellationToken).ConfigureAwait(false); + await SendMessageToSession(session, SessionMessageType.SyncPlayCommand, command, cancellationToken).ConfigureAwait(false); } /// @@ -1194,7 +1194,7 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); - await SendMessageToSession(session, "SyncPlayGroupUpdate", command, cancellationToken).ConfigureAwait(false); + await SendMessageToSession(session, SessionMessageType.SyncPlayGroupUpdate, command, cancellationToken).ConfigureAwait(false); } private IEnumerable TranslateItemForPlayback(Guid id, User user) @@ -1297,7 +1297,7 @@ namespace Emby.Server.Implementations.Session } } - return SendMessageToSession(session, "Playstate", command, cancellationToken); + return SendMessageToSession(session, SessionMessageType.PlayState, command, cancellationToken); } private static void AssertCanControl(SessionInfo session, SessionInfo controllingSession) @@ -1322,7 +1322,7 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); - return SendMessageToSessions(Sessions, "RestartRequired", string.Empty, cancellationToken); + return SendMessageToSessions(Sessions, SessionMessageType.RestartRequired, string.Empty, cancellationToken); } /// @@ -1334,7 +1334,7 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); - return SendMessageToSessions(Sessions, "ServerShuttingDown", string.Empty, cancellationToken); + return SendMessageToSessions(Sessions, SessionMessageType.ServerShuttingDown, string.Empty, cancellationToken); } /// @@ -1348,7 +1348,7 @@ namespace Emby.Server.Implementations.Session _logger.LogDebug("Beginning SendServerRestartNotification"); - return SendMessageToSessions(Sessions, "ServerRestarting", string.Empty, cancellationToken); + return SendMessageToSessions(Sessions, SessionMessageType.ServerRestarting, string.Empty, cancellationToken); } /// @@ -1866,7 +1866,7 @@ namespace Emby.Server.Implementations.Session } /// - public Task SendMessageToAdminSessions(string name, T data, CancellationToken cancellationToken) + public Task SendMessageToAdminSessions(SessionMessageType name, T data, CancellationToken cancellationToken) { CheckDisposed(); @@ -1879,7 +1879,7 @@ namespace Emby.Server.Implementations.Session } /// - public Task SendMessageToUserSessions(List userIds, string name, Func dataFn, CancellationToken cancellationToken) + public Task SendMessageToUserSessions(List userIds, SessionMessageType name, Func dataFn, CancellationToken cancellationToken) { CheckDisposed(); @@ -1894,7 +1894,7 @@ namespace Emby.Server.Implementations.Session } /// - public Task SendMessageToUserSessions(List userIds, string name, T data, CancellationToken cancellationToken) + public Task SendMessageToUserSessions(List userIds, SessionMessageType name, T data, CancellationToken cancellationToken) { CheckDisposed(); @@ -1903,7 +1903,7 @@ namespace Emby.Server.Implementations.Session } /// - public Task SendMessageToUserDeviceSessions(string deviceId, string name, T data, CancellationToken cancellationToken) + public Task SendMessageToUserDeviceSessions(string deviceId, SessionMessageType name, T data, CancellationToken cancellationToken) { CheckDisposed(); diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 15c2af220..a5f847953 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -8,6 +8,7 @@ using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -316,7 +317,7 @@ namespace Emby.Server.Implementations.Session return webSocket.SendAsync( new WebSocketMessage { - MessageType = "ForceKeepAlive", + MessageType = SessionMessageType.ForceKeepAlive, Data = WebSocketLostTimeout }, CancellationToken.None); diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index 94604ca1e..b986ffa1c 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session @@ -65,7 +66,7 @@ namespace Emby.Server.Implementations.Session /// public Task SendMessage( - string name, + SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken) -- cgit v1.2.3 From 5a7dda337f4cdda0d0c61adef3d2b13772e708d0 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 11:50:00 -0400 Subject: Add active session tracking Adds a flag for a maximum number of user sessions, as well as an authentication check to ensure that the user is not above this level. --- Emby.Server.Implementations/Session/SessionManager.cs | 13 +++++++++++++ Jellyfin.Data/Entities/User.cs | 5 +++++ Jellyfin.Server.Implementations/Users/UserManager.cs | 2 ++ MediaBrowser.Model/Users/UserPolicy.cs | 6 ++++++ 4 files changed, 26 insertions(+) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index e42d47853..5903d395a 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1484,6 +1484,19 @@ namespace Emby.Server.Implementations.Session throw new SecurityException("User is not allowed access from this device."); } + var sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; + int maxActiveSessions = user.MaxActiveSessions; + _logger.LogDebug("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); + if (maxActiveSessions >= 0 && sessionsCount >= maxActiveSessions) + { + throw new SecurityException( + "User {User} is at their maximum number of sessions ({Sessions}/{Max}).", + user.Username, + sessionsCount, + maxActiveSessions + ) + } + var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); var session = LogSessionActivity( diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index f7ab57a1b..daa4de0b5 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -188,6 +188,11 @@ namespace Jellyfin.Data.Entities /// public int? LoginAttemptsBeforeLockout { get; set; } + /// + /// Gets or sets the maximum number of active sessions the user can have at once. + /// + public int? MaxActiveSessions { get; set; } + /// /// Gets or sets the subtitle mode. /// diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 8f04baa08..43698efb7 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -379,6 +379,7 @@ namespace Jellyfin.Server.Implementations.Users PasswordResetProviderId = user.PasswordResetProviderId, InvalidLoginAttemptCount = user.InvalidLoginAttemptCount, LoginAttemptsBeforeLockout = user.LoginAttemptsBeforeLockout ?? -1, + MaxActiveSessions = user.MaxActiveSessions ?? -1, IsAdministrator = user.HasPermission(PermissionKind.IsAdministrator), IsHidden = user.HasPermission(PermissionKind.IsHidden), IsDisabled = user.HasPermission(PermissionKind.IsDisabled), @@ -701,6 +702,7 @@ namespace Jellyfin.Server.Implementations.Users user.PasswordResetProviderId = policy.PasswordResetProviderId; user.InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount; user.LoginAttemptsBeforeLockout = maxLoginAttempts; + user.MaxActiveSessions = policy.MaxActiveSessions; user.SyncPlayAccess = policy.SyncPlayAccess; user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator); user.SetPermission(PermissionKind.IsHidden, policy.IsHidden); diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index a1f01f7e8..53dcb6bbd 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -92,6 +92,10 @@ namespace MediaBrowser.Model.Users public int LoginAttemptsBeforeLockout { get; set; } + public int ActiveSessionCount { get; set; } + + public int MaxActiveSessions { get; set; } + public bool EnablePublicSharing { get; set; } public Guid[] BlockedMediaFolders { get; set; } @@ -144,6 +148,8 @@ namespace MediaBrowser.Model.Users LoginAttemptsBeforeLockout = -1; + MaxActiveSessions = -1; + EnableAllChannels = true; EnabledChannels = Array.Empty(); -- cgit v1.2.3 From 975fca51583de23bafb6720104a2a6857ab29b18 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 13:19:56 -0400 Subject: Fix syntax error --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 5903d395a..ac59fe386 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1494,7 +1494,7 @@ namespace Emby.Server.Implementations.Session user.Username, sessionsCount, maxActiveSessions - ) + ); } var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); -- cgit v1.2.3 From b130af1b0c869fa6a35be4a53510e0f0fa4ad0d3 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 13:29:18 -0400 Subject: Remove variables from SecurityException --- Emby.Server.Implementations/Session/SessionManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index ac59fe386..46fa29919 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1489,12 +1489,7 @@ namespace Emby.Server.Implementations.Session _logger.LogDebug("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 0 && sessionsCount >= maxActiveSessions) { - throw new SecurityException( - "User {User} is at their maximum number of sessions ({Sessions}/{Max}).", - user.Username, - sessionsCount, - maxActiveSessions - ); + throw new SecurityException("User is at their maximum number of sessions."); } var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); -- cgit v1.2.3 From 6e1d1eed23442976ac0d9b2a2af44b7a6804ea09 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 13:30:21 -0400 Subject: Make log entry informational --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 46fa29919..cd40bda55 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1486,7 +1486,7 @@ namespace Emby.Server.Implementations.Session var sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; int maxActiveSessions = user.MaxActiveSessions; - _logger.LogDebug("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); + _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 0 && sessionsCount >= maxActiveSessions) { throw new SecurityException("User is at their maximum number of sessions."); -- cgit v1.2.3 From d0ec6872f3418a3bc6bacff6ba068526f45fc167 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 14:06:20 -0400 Subject: Increase count check to 1 There's another way to disable a user anyways. --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index cd40bda55..90363e560 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1487,7 +1487,7 @@ namespace Emby.Server.Implementations.Session var sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; int maxActiveSessions = user.MaxActiveSessions; _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); - if (maxActiveSessions >= 0 && sessionsCount >= maxActiveSessions) + if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions) { throw new SecurityException("User is at their maximum number of sessions."); } -- cgit v1.2.3 From 8dfa2015d0e804227fe9db09caf21315da7495e4 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 14:14:42 -0400 Subject: Make the count an int for cleanliness --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 90363e560..04becff49 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1484,7 +1484,7 @@ namespace Emby.Server.Implementations.Session throw new SecurityException("User is not allowed access from this device."); } - var sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; + int sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; int maxActiveSessions = user.MaxActiveSessions; _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions) -- cgit v1.2.3 From 5aa519fd399d8b09a360f6448acc992225f8c219 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 15:46:57 -0400 Subject: Implement better count method --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 04becff49..d283ee8d8 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1484,7 +1484,7 @@ namespace Emby.Server.Implementations.Session throw new SecurityException("User is not allowed access from this device."); } - int sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; + int sessionsCount = Sessions.Count(i => string.Equals(i.UserId, user.Id, StringComparison.OrdinalIgnoreCase)); int maxActiveSessions = user.MaxActiveSessions; _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions) -- cgit v1.2.3 From df177b47524c0f7c5df21f32ebeaba5576d3f8a4 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 15:52:39 -0400 Subject: Revert "Implement better count method" This reverts commit 5aa519fd399d8b09a360f6448acc992225f8c219. --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index d283ee8d8..04becff49 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1484,7 +1484,7 @@ namespace Emby.Server.Implementations.Session throw new SecurityException("User is not allowed access from this device."); } - int sessionsCount = Sessions.Count(i => string.Equals(i.UserId, user.Id, StringComparison.OrdinalIgnoreCase)); + int sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; int maxActiveSessions = user.MaxActiveSessions; _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions) -- cgit v1.2.3 From 67e89dd5255a8ae38e0f0f489595d290e718b7a1 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 4 Oct 2020 16:57:48 -0400 Subject: Use nicer count comparitor --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 04becff49..fa4caeb18 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1484,7 +1484,7 @@ namespace Emby.Server.Implementations.Session throw new SecurityException("User is not allowed access from this device."); } - int sessionsCount = Sessions.Where(i => string.Equals(i.UserId, user.Id)).ToList().Count; + int sessionsCount = Sessions.Count(i => i.UserId.Equals(user.Id)); int maxActiveSessions = user.MaxActiveSessions; _logger.LogInformation("Current/Max sessions for user {User}: {Sessions}/{Max}", user.Username, sessionsCount, maxActiveSessions); if (maxActiveSessions >= 1 && sessionsCount >= maxActiveSessions) -- cgit v1.2.3 From 3d69bcd19090a3e467594375db3ee25f39e3def9 Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 6 Oct 2020 08:14:56 +0200 Subject: Fix playbackstart not triggering in the new eventmanager --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b1ab20da2..607b322f2 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -666,7 +666,7 @@ namespace Emby.Server.Implementations.Session } } - var eventArgs = new PlaybackProgressEventArgs + var eventArgs = new PlaybackStartEventArgs { Item = libraryItem, Users = users, -- cgit v1.2.3