| 
					
				 | 
			
			
				@@ -1,5 +1,3 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#nullable disable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Collections.Concurrent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Globalization; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -9,7 +7,6 @@ using MediaBrowser.Common.Extensions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Authentication; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Configuration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Controller.Net; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.QuickConnect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Security; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.QuickConnect; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -22,14 +19,28 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public class QuickConnectManager : IQuickConnect, IDisposable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly ConcurrentDictionary<string, QuickConnectResult> _currentRequests = new ConcurrentDictionary<string, QuickConnectResult>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// The name of internal access tokens. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private const string TokenName = "QuickConnect"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// The length of user facing codes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private const int CodeLength = 6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// The time (in minutes) that the quick connect token is valid. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private const int Timeout = 10; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly RNGCryptoServiceProvider _rng = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly ConcurrentDictionary<string, QuickConnectResult> _currentRequests = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly IServerConfigurationManager _config; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly ILogger<QuickConnectManager> _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IAuthenticationRepository _authenticationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IAuthorizationContext _authContext; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly IServerApplicationHost _appHost; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IAuthenticationRepository _authenticationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Initializes a new instance of the <see cref="QuickConnectManager"/> class. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -38,86 +49,42 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="config">Configuration.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="logger">Logger.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="appHost">Application host.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <param name="authContext">Authentication context.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="authenticationRepository">Authentication repository.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public QuickConnectManager( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IServerConfigurationManager config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ILogger<QuickConnectManager> logger, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IServerApplicationHost appHost, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IAuthorizationContext authContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IAuthenticationRepository authenticationRepository) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _config = config; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _appHost = appHost; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _authContext = authContext; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _authenticationRepository = authenticationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ReloadConfiguration(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public int CodeLength { get; set; } = 6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string TokenName { get; set; } = "QuickConnect"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public bool IsEnabled => _config.Configuration.QuickConnectAvailable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public int Timeout { get; set; } = 5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private DateTime DateActivated { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void AssertActive() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Assert that quick connect is currently active and throws an exception if it is not. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AssertActive() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (State != QuickConnectState.Active) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!IsEnabled) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ArgumentException("Quick connect is not active on this server"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new AuthenticationException("Quick connect is not active on this server"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void Activate() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            DateActivated = DateTime.UtcNow; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            SetState(QuickConnectState.Active); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void SetState(QuickConnectState newState) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogDebug("Changed quick connect state from {State} to {newState}", State, newState); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ExpireRequests(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            State = newState; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _config.Configuration.QuickConnectAvailable = newState == QuickConnectState.Available || newState == QuickConnectState.Active; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _config.SaveConfiguration(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogDebug("Configuration saved"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public QuickConnectResult TryConnect() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AssertActive(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ExpireRequests(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (State != QuickConnectState.Active) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _logger.LogDebug("Refusing quick connect initiation request, current state is {State}", State); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new AuthenticationException("Quick connect is not active on this server"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var secret = GenerateSecureRandom(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var code = GenerateCode(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var result = new QuickConnectResult() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Secret = GenerateSecureRandom(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                DateAdded = DateTime.UtcNow, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Code = code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var result = new QuickConnectResult(secret, code, DateTime.UtcNow); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentRequests[code] = result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return result; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -126,12 +93,12 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public QuickConnectResult CheckRequestStatus(string secret) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ExpireRequests(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             AssertActive(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ExpireRequests(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             string code = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Code).DefaultIfEmpty(string.Empty).First(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_currentRequests.TryGetValue(code, out QuickConnectResult? result)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 throw new ResourceNotFoundException("Unable to find request with provided secret"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -139,8 +106,11 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string GenerateCode() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Generates a short code to display to the user to uniquely identify this request. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns>A short, unique alphanumeric string.</returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string GenerateCode() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Span<byte> raw = stackalloc byte[4]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -161,10 +131,10 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public bool AuthorizeRequest(Guid userId, string code) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ExpireRequests(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             AssertActive(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ExpireRequests(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_currentRequests.TryGetValue(code, out QuickConnectResult? result)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 throw new ResourceNotFoundException("Unable to find request"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -174,16 +144,16 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 throw new InvalidOperationException("Request is already authorized"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var token = Guid.NewGuid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result.Authentication = token; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Change the time on the request so it expires one minute into the future. It can't expire immediately as otherwise some clients wouldn't ever see that they have been authenticated. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var added = result.DateAdded ?? DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(Timeout)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            result.DateAdded = added.Subtract(TimeSpan.FromMinutes(Timeout - 1)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result.DateAdded = DateTime.Now.Add(TimeSpan.FromMinutes(1)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _authenticationRepository.Create(new AuthenticationInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 AppName = TokenName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                AccessToken = result.Authentication, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                AccessToken = token.ToString("N", CultureInfo.InvariantCulture), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 DateCreated = DateTime.UtcNow, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 DeviceId = _appHost.SystemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 DeviceName = _appHost.FriendlyName, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -196,28 +166,6 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public int DeleteAllDevices(Guid user) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var raw = _authenticationRepository.Get(new AuthenticationInfoQuery() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                DeviceId = _appHost.SystemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                UserId = user 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenName, StringComparison.Ordinal)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var removed = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (var token in tokens) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _authenticationRepository.Delete(token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _logger.LogDebug("Deleted token {AccessToken}", token.AccessToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                removed++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return removed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Dispose. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -235,7 +183,7 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (disposing) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _rng?.Dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _rng.Dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -247,22 +195,19 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return Convert.ToHexString(bytes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void ExpireRequests(bool expireAll = false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="expireAll">If true, all requests will be expired.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void ExpireRequests(bool expireAll = false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Check if quick connect should be deactivated 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (State == QuickConnectState.Active && DateTime.UtcNow > DateActivated.AddMinutes(Timeout) && !expireAll) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _logger.LogDebug("Quick connect time expired, deactivating"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                SetState(QuickConnectState.Available); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                expireAll = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // All requests before this timestamp have expired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var minTime = DateTime.UtcNow.AddMinutes(-Timeout); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Expire stale connection requests 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             foreach (var (_, currentRequest) in _currentRequests) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var added = currentRequest.DateAdded ?? DateTime.UnixEpoch; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (expireAll || DateTime.UtcNow > added.AddMinutes(Timeout)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (expireAll || currentRequest.DateAdded > minTime) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     var code = currentRequest.Code; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     _logger.LogDebug("Removing expired request {Code}", code); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -274,10 +219,5 @@ namespace Emby.Server.Implementations.QuickConnect 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void ReloadConfiguration() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            State = _config.Configuration.QuickConnectAvailable ? QuickConnectState.Available : QuickConnectState.Unavailable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |