From 36f3e933a23d802d154c16fd304a82c3fe3f453d Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Wed, 15 Apr 2020 14:28:42 -0500 Subject: Add quick connect --- .../QuickConnect/QuickConnectResult.cs | 50 ++++++++++++++++++++ .../QuickConnect/QuickConnectResultDto.cs | 53 ++++++++++++++++++++++ .../QuickConnect/QuickConnectState.cs | 23 ++++++++++ 3 files changed, 126 insertions(+) create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResult.cs create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectState.cs (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs new file mode 100644 index 000000000..bc3fd0046 --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -0,0 +1,50 @@ +using System; + +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Stores the result of an incoming quick connect request. + /// + public class QuickConnectResult + { + /// + /// Gets a value indicating whether this request is authorized. + /// + public bool Authenticated => !string.IsNullOrEmpty(Authentication); + + /// + /// Gets or sets the secret value used to uniquely identify this request. Can be used to retrieve authentication information. + /// + public string Secret { get; set; } + + /// + /// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request. + /// + public string Lookup { get; set; } + + /// + /// Gets or sets the user facing code used so the user can quickly differentiate this request from others. + /// + public string Code { get; set; } + + /// + /// Gets or sets the device friendly name. + /// + public string FriendlyName { get; set; } + + /// + /// Gets or sets the private access token. + /// + public string Authentication { get; set; } + + /// + /// Gets or sets an error message. + /// + public string Error { get; set; } + + /// + /// Gets or sets the DateTime that this request was created. + /// + public DateTime DateAdded { get; set; } + } +} diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs new file mode 100644 index 000000000..671b7cc94 --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs @@ -0,0 +1,53 @@ +using System; + +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Stores the non-sensitive results of an incoming quick connect request. + /// + public class QuickConnectResultDto + { + /// + /// Gets a value indicating whether this request is authorized. + /// + public bool Authenticated { get; private set; } + + /// + /// Gets the user facing code used so the user can quickly differentiate this request from others. + /// + public string Code { get; private set; } + + /// + /// Gets the public value used to uniquely identify this request. Can only be used to authorize the request. + /// + public string Lookup { get; private set; } + + /// + /// Gets the device friendly name. + /// + public string FriendlyName { get; private set; } + + /// + /// Gets the DateTime that this request was created. + /// + public DateTime DateAdded { get; private set; } + + /// + /// Cast an internal quick connect result to a DTO by removing all sensitive properties. + /// + /// QuickConnectResult object to cast + public static implicit operator QuickConnectResultDto(QuickConnectResult result) + { + QuickConnectResultDto resultDto = new QuickConnectResultDto + { + Authenticated = result.Authenticated, + Code = result.Code, + FriendlyName = result.FriendlyName, + DateAdded = result.DateAdded, + Lookup = result.Lookup + }; + + return resultDto; + } + } +} diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs new file mode 100644 index 000000000..9f250519b --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Quick connect state. + /// + public enum QuickConnectState + { + /// + /// This feature has not been opted into and is unavailable until the server administrator chooses to opt-in. + /// + Unavailable, + + /// + /// The feature is enabled for use on the server but is not currently accepting connection requests. + /// + Available, + + /// + /// The feature is actively accepting connection requests. + /// + Active + } +} -- cgit v1.2.3 From 70e50dfa90575cc5e906be1509d3ed363eb1ada4 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Fri, 24 Apr 2020 18:51:19 -0500 Subject: Apply suggestions from code review --- .../QuickConnect/ConfigurationExtension.cs | 2 -- Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs | 8 +++----- MediaBrowser.Model/QuickConnect/QuickConnectState.cs | 6 +++--- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs index 0e35ba80a..458bb7614 100644 --- a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs +++ b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; using MediaBrowser.Common.Configuration; diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index e24dc3a67..b8b51adb6 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.QuickConnect /// Should only be called at server startup when a singleton is created. /// /// Configuration. - /// Logger. + /// Logger. /// User manager. /// Localization. /// JSON serializer. @@ -52,7 +52,7 @@ namespace Emby.Server.Implementations.QuickConnect /// Task scheduler. public QuickConnectManager( IServerConfigurationManager config, - ILoggerFactory loggerFactory, + ILogger logger, IUserManager userManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.QuickConnect ITaskManager taskManager) { _config = config; - _logger = loggerFactory.CreateLogger(nameof(QuickConnectManager)); + _logger = logger; _userManager = userManager; _localizationManager = localization; _jsonSerializer = jsonSerializer; @@ -196,8 +196,6 @@ namespace Emby.Server.Implementations.QuickConnect /// public string GenerateCode() { - // TODO: output may be biased - int min = (int)Math.Pow(10, CodeLength - 1); int max = (int)Math.Pow(10, CodeLength); diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs index 9f250519b..f1074f25f 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs @@ -8,16 +8,16 @@ namespace MediaBrowser.Model.QuickConnect /// /// This feature has not been opted into and is unavailable until the server administrator chooses to opt-in. /// - Unavailable, + Unavailable = 0, /// /// The feature is enabled for use on the server but is not currently accepting connection requests. /// - Available, + Available = 1, /// /// The feature is actively accepting connection requests. /// - Active + Active = 2 } } -- cgit v1.2.3 From 0d6a63bf84d7ad971128c6ba6cad77e76e023536 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 8 Jun 2020 15:48:18 -0500 Subject: Make all properties nullable --- .../QuickConnect/ConfigurationExtension.cs | 2 ++ .../QuickConnect/QuickConnectConfiguration.cs | 2 ++ .../QuickConnect/QuickConnectManager.cs | 10 ++++++---- MediaBrowser.Model/QuickConnect/QuickConnectResult.cs | 14 +++++++------- MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs | 8 ++++---- 5 files changed, 21 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs index 458bb7614..0e35ba80a 100644 --- a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs +++ b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Common.Configuration; diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs index befc46379..11e558bae 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Model.QuickConnect; namespace Emby.Server.Implementations.QuickConnect diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index b8b51adb6..929e021a3 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -234,7 +234,8 @@ namespace Emby.Server.Implementations.QuickConnect result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); // Advance the time on the request so it expires sooner as the client will pick up the changes in a few seconds - result.DateAdded = result.DateAdded.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); + var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, RequestExpiry, 0)); + result.DateAdded = added.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); _authenticationRepository.Create(new AuthenticationInfo { @@ -284,7 +285,7 @@ namespace Emby.Server.Implementations.QuickConnect { bool expireAll = false; - // check if quick connect should be deactivated + // Check if quick connect should be deactivated if (TemporaryActivation && DateTime.Now > DateActivated.AddMinutes(10) && State == QuickConnectState.Active) { _logger.LogDebug("Quick connect time expired, deactivating"); @@ -293,13 +294,14 @@ namespace Emby.Server.Implementations.QuickConnect TemporaryActivation = false; } - // expire stale connection requests + // Expire stale connection requests var delete = new List(); var values = _currentRequests.Values.ToList(); for (int i = 0; i < _currentRequests.Count; i++) { - if (DateTime.Now > values[i].DateAdded.AddMinutes(RequestExpiry) || expireAll) + var added = values[i].DateAdded ?? DateTime.UnixEpoch; + if (DateTime.Now > added.AddMinutes(RequestExpiry) || expireAll) { delete.Add(values[i].Lookup); } diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs index bc3fd0046..32d7f6aba 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -15,36 +15,36 @@ namespace MediaBrowser.Model.QuickConnect /// /// Gets or sets the secret value used to uniquely identify this request. Can be used to retrieve authentication information. /// - public string Secret { get; set; } + public string? Secret { get; set; } /// /// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request. /// - public string Lookup { get; set; } + public string? Lookup { get; set; } /// /// Gets or sets the user facing code used so the user can quickly differentiate this request from others. /// - public string Code { get; set; } + public string? Code { get; set; } /// /// Gets or sets the device friendly name. /// - public string FriendlyName { get; set; } + public string? FriendlyName { get; set; } /// /// Gets or sets the private access token. /// - public string Authentication { get; set; } + public string? Authentication { get; set; } /// /// Gets or sets an error message. /// - public string Error { get; set; } + public string? Error { get; set; } /// /// Gets or sets the DateTime that this request was created. /// - public DateTime DateAdded { get; set; } + public DateTime? DateAdded { get; set; } } } diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs index 671b7cc94..19acc7cd8 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs @@ -15,22 +15,22 @@ namespace MediaBrowser.Model.QuickConnect /// /// Gets the user facing code used so the user can quickly differentiate this request from others. /// - public string Code { get; private set; } + public string? Code { get; private set; } /// /// Gets the public value used to uniquely identify this request. Can only be used to authorize the request. /// - public string Lookup { get; private set; } + public string? Lookup { get; private set; } /// /// Gets the device friendly name. /// - public string FriendlyName { get; private set; } + public string? FriendlyName { get; private set; } /// /// Gets the DateTime that this request was created. /// - public DateTime DateAdded { get; private set; } + public DateTime? DateAdded { get; private set; } /// /// Cast an internal quick connect result to a DTO by removing all sensitive properties. -- cgit v1.2.3 From 4be476ec5312387f87134915d0fd132b2ad5fa3f Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 18 Jun 2020 01:29:47 -0500 Subject: Move all settings into the main server configuration Decreased the timeout from 30 minutes to 5. Public lookup values have been replaced with the short code. --- .../QuickConnect/ConfigurationExtension.cs | 20 ------- .../QuickConnect/QuickConnectConfiguration.cs | 15 ----- .../QuickConnectConfigurationFactory.cs | 27 --------- .../QuickConnect/QuickConnectManager.cs | 66 ++++++++++------------ .../QuickConnect/IQuickConnect.cs | 8 +-- .../Configuration/ServerConfiguration.cs | 6 ++ .../QuickConnect/QuickConnectResult.cs | 5 -- .../QuickConnect/QuickConnectResultDto.cs | 14 +---- 8 files changed, 41 insertions(+), 120 deletions(-) delete mode 100644 Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs delete mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs delete mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs deleted file mode 100644 index 2a19fc36c..000000000 --- a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MediaBrowser.Common.Configuration; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// - /// Configuration extension to support persistent quick connect configuration. - /// - public static class ConfigurationExtension - { - /// - /// Return the current quick connect configuration. - /// - /// Configuration manager. - /// Current quick connect configuration. - public static QuickConnectConfiguration GetQuickConnectConfiguration(this IConfigurationManager manager) - { - return manager.GetConfiguration("quickconnect"); - } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs deleted file mode 100644 index 2302ddbc3..000000000 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MediaBrowser.Model.QuickConnect; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// - /// Persistent quick connect configuration. - /// - public class QuickConnectConfiguration - { - /// - /// Gets or sets persistent quick connect availability state. - /// - public QuickConnectState State { get; set; } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs deleted file mode 100644 index d7bc84c5e..000000000 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// - /// Configuration factory for quick connect. - /// - public class QuickConnectConfigurationFactory : IConfigurationFactory - { - /// - /// Returns the current quick connect configuration. - /// - /// Current quick connect configuration. - public IEnumerable GetConfigurations() - { - return new[] - { - new ConfigurationStore - { - Key = "quickconnect", - ConfigurationType = typeof(QuickConnectConfiguration) - } - }; - } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 7a584c7cd..8d704f32b 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -11,7 +11,9 @@ using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Controller.Security; using MediaBrowser.Model.QuickConnect; using MediaBrowser.Model.Services; +using MediaBrowser.Common; using Microsoft.Extensions.Logging; +using MediaBrowser.Common.Extensions; namespace Emby.Server.Implementations.QuickConnect { @@ -64,9 +66,7 @@ namespace Emby.Server.Implementations.QuickConnect public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; /// - public int RequestExpiry { get; set; } = 30; - - private bool TemporaryActivation { get; set; } = false; + public int Timeout { get; set; } = 5; private DateTime DateActivated { get; set; } @@ -82,10 +82,9 @@ namespace Emby.Server.Implementations.QuickConnect /// public QuickConnectResult Activate() { - // This should not call SetEnabled since that would persist the "temporary" activation to the configuration file - State = QuickConnectState.Active; + SetEnabled(QuickConnectState.Active); + DateActivated = DateTime.Now; - TemporaryActivation = true; return new QuickConnectResult(); } @@ -96,12 +95,10 @@ namespace Emby.Server.Implementations.QuickConnect _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); ExpireRequests(true); - State = newState; - _config.SaveConfiguration("quickconnect", new QuickConnectConfiguration() - { - State = State - }); + State = newState; + _config.Configuration.QuickConnectAvailable = newState == QuickConnectState.Available || newState == QuickConnectState.Active; + _config.SaveConfiguration(); _logger.LogDebug("Configuration saved"); } @@ -123,17 +120,16 @@ namespace Emby.Server.Implementations.QuickConnect _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); - var lookup = GenerateSecureRandom(); + var code = GenerateCode(); var result = new QuickConnectResult() { - Lookup = lookup, Secret = GenerateSecureRandom(), FriendlyName = friendlyName, DateAdded = DateTime.Now, - Code = GenerateCode() + Code = code }; - _currentRequests[lookup] = result; + _currentRequests[code] = result; return result; } @@ -143,17 +139,16 @@ namespace Emby.Server.Implementations.QuickConnect ExpireRequests(); AssertActive(); - string lookup = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Lookup).DefaultIfEmpty(string.Empty).First(); + string code = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Code).DefaultIfEmpty(string.Empty).First(); - if (!_currentRequests.TryGetValue(lookup, out QuickConnectResult result)) + if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { - throw new KeyNotFoundException("Unable to find request with provided identifier"); + throw new ResourceNotFoundException("Unable to find request with provided secret"); } return result; } - /// public List GetCurrentRequests() { return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); @@ -186,16 +181,16 @@ namespace Emby.Server.Implementations.QuickConnect } /// - public bool AuthorizeRequest(IRequest request, string lookup) + public bool AuthorizeRequest(IRequest request, string code) { ExpireRequests(); AssertActive(); var auth = _authContext.GetAuthorizationInfo(request); - if (!_currentRequests.TryGetValue(lookup, out QuickConnectResult result)) + if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { - throw new KeyNotFoundException("Unable to find request"); + throw new ResourceNotFoundException("Unable to find request"); } if (result.Authenticated) @@ -205,9 +200,9 @@ namespace Emby.Server.Implementations.QuickConnect result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - // Advance the time on the request so it expires sooner as the client will pick up the changes in a few seconds - var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, RequestExpiry, 0)); - result.DateAdded = added.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); + // 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.Now.Subtract(new TimeSpan(0, Timeout, 0)); + result.DateAdded = added.Subtract(new TimeSpan(0, Timeout - 1, 0)); _authenticationRepository.Create(new AuthenticationInfo { @@ -271,7 +266,7 @@ namespace Emby.Server.Implementations.QuickConnect var bytes = new byte[length]; _rng.GetBytes(bytes); - return string.Join(string.Empty, bytes.Select(x => x.ToString("x2", CultureInfo.InvariantCulture))); + return Hex.Encode(bytes); } /// @@ -281,12 +276,11 @@ namespace Emby.Server.Implementations.QuickConnect private void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated - if (TemporaryActivation && DateTime.Now > DateActivated.AddMinutes(10) && State == QuickConnectState.Active && !expireAll) + if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) { _logger.LogDebug("Quick connect time expired, deactivating"); SetEnabled(QuickConnectState.Available); expireAll = true; - TemporaryActivation = false; } // Expire stale connection requests @@ -296,28 +290,28 @@ namespace Emby.Server.Implementations.QuickConnect for (int i = 0; i < values.Count; i++) { var added = values[i].DateAdded ?? DateTime.UnixEpoch; - if (DateTime.Now > added.AddMinutes(RequestExpiry) || expireAll) + if (DateTime.Now > added.AddMinutes(Timeout) || expireAll) { - delete.Add(values[i].Lookup); + delete.Add(values[i].Code); } } - foreach (var lookup in delete) + foreach (var code in delete) { - _logger.LogDebug("Removing expired request {lookup}", lookup); + _logger.LogDebug("Removing expired request {code}", code); - if (!_currentRequests.TryRemove(lookup, out _)) + if (!_currentRequests.TryRemove(code, out _)) { - _logger.LogWarning("Request {lookup} already expired", lookup); + _logger.LogWarning("Request {code} already expired", code); } } } private void ReloadConfiguration() { - var config = _config.GetQuickConnectConfiguration(); + var available = _config.Configuration.QuickConnectAvailable; - State = config.State; + State = available ? QuickConnectState.Available : QuickConnectState.Unavailable; } } } diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index d44765e11..d31d0e509 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Controller.QuickConnect public QuickConnectState State { get; } /// - /// Gets or sets the time (in minutes) before a pending request will expire. + /// Gets or sets the time (in minutes) before quick connect will automatically deactivate. /// - public int RequestExpiry { get; set; } + public int Timeout { get; set; } /// /// Assert that quick connect is currently active and throws an exception if it is not. @@ -77,9 +77,9 @@ namespace MediaBrowser.Controller.QuickConnect /// Authorizes a quick connect request to connect as the calling user. /// /// HTTP request object. - /// Public request lookup value. + /// Identifying code for the request.. /// A boolean indicating if the authorization completed successfully. - bool AuthorizeRequest(IRequest request, string lookup); + bool AuthorizeRequest(IRequest request, string code); /// /// Deletes all quick connect access tokens for the provided user. diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index afbe02dd3..76b290606 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -76,6 +76,11 @@ namespace MediaBrowser.Model.Configuration /// true if this instance is port authorized; otherwise, false. public bool IsPortAuthorized { get; set; } + /// + /// Gets or sets if quick connect is available for use on this server. + /// + public bool QuickConnectAvailable { get; set; } + public bool AutoRunWebApp { get; set; } public bool EnableRemoteAccess { get; set; } @@ -281,6 +286,7 @@ namespace MediaBrowser.Model.Configuration AutoRunWebApp = true; EnableRemoteAccess = true; + QuickConnectAvailable = false; EnableUPnP = false; MinResumePct = 5; diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs index 32d7f6aba..a10d60d57 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -17,11 +17,6 @@ namespace MediaBrowser.Model.QuickConnect /// public string? Secret { get; set; } - /// - /// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request. - /// - public string? Lookup { get; set; } - /// /// Gets or sets the user facing code used so the user can quickly differentiate this request from others. /// diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs index 19acc7cd8..26084caf1 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs @@ -17,25 +17,15 @@ namespace MediaBrowser.Model.QuickConnect /// public string? Code { get; private set; } - /// - /// Gets the public value used to uniquely identify this request. Can only be used to authorize the request. - /// - public string? Lookup { get; private set; } - /// /// Gets the device friendly name. /// public string? FriendlyName { get; private set; } - /// - /// Gets the DateTime that this request was created. - /// - public DateTime? DateAdded { get; private set; } - /// /// Cast an internal quick connect result to a DTO by removing all sensitive properties. /// - /// QuickConnectResult object to cast + /// QuickConnectResult object to cast. public static implicit operator QuickConnectResultDto(QuickConnectResult result) { QuickConnectResultDto resultDto = new QuickConnectResultDto @@ -43,8 +33,6 @@ namespace MediaBrowser.Model.QuickConnect Authenticated = result.Authenticated, Code = result.Code, FriendlyName = result.FriendlyName, - DateAdded = result.DateAdded, - Lookup = result.Lookup }; return resultDto; -- cgit v1.2.3 From 329980c727cf03587ff5f4011a3af3ef2fa5e4f1 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 18 Jun 2020 01:58:58 -0500 Subject: API cleanup --- .../QuickConnect/QuickConnectManager.cs | 35 +++-------- .../QuickConnect/QuickConnectService.cs | 67 ++++------------------ .../QuickConnect/IQuickConnect.cs | 23 +++----- .../QuickConnect/QuickConnectResultDto.cs | 41 ------------- 4 files changed, 27 insertions(+), 139 deletions(-) delete mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 8d704f32b..263556e9d 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -75,18 +75,15 @@ namespace Emby.Server.Implementations.QuickConnect { if (State != QuickConnectState.Active) { - throw new InvalidOperationException("Quick connect is not active on this server"); + throw new ArgumentException("Quick connect is not active on this server"); } } /// - public QuickConnectResult Activate() + public void Activate() { - SetEnabled(QuickConnectState.Active); - DateActivated = DateTime.Now; - - return new QuickConnectResult(); + SetEnabled(QuickConnectState.Active); } /// @@ -149,19 +146,6 @@ namespace Emby.Server.Implementations.QuickConnect return result; } - public List GetCurrentRequests() - { - return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); - } - - /// - public List GetCurrentRequestsInternal() - { - ExpireRequests(); - AssertActive(); - return _currentRequests.Values.ToList(); - } - /// public string GenerateCode() { @@ -215,7 +199,7 @@ namespace Emby.Server.Implementations.QuickConnect UserId = auth.UserId }); - _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Name, result.Code); + _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Username, result.Code); return true; } @@ -269,11 +253,8 @@ namespace Emby.Server.Implementations.QuickConnect return Hex.Encode(bytes); } - /// - /// Expire quick connect requests that are over the time limit. If is true, all requests are unconditionally expired. - /// - /// If true, all requests will be expired. - private void ExpireRequests(bool expireAll = false) + /// + public void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) @@ -309,9 +290,7 @@ namespace Emby.Server.Implementations.QuickConnect private void ReloadConfiguration() { - var available = _config.Configuration.QuickConnectAvailable; - - State = available ? QuickConnectState.Available : QuickConnectState.Unavailable; + State = _config.Configuration.QuickConnectAvailable ? QuickConnectState.Available : QuickConnectState.Unavailable; } } } diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs index 60d6ac414..9047a1e95 100644 --- a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs +++ b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; @@ -24,18 +23,12 @@ namespace MediaBrowser.Api.QuickConnect public string Secret { get; set; } } - [Route("/QuickConnect/List", "GET", Summary = "Lists all quick connect requests")] - [Authenticated] - public class QuickConnectList : IReturn> - { - } - [Route("/QuickConnect/Authorize", "POST", Summary = "Authorizes a pending quick connect request")] [Authenticated] - public class Authorize : IReturn + public class Authorize : IReturn { - [ApiMember(Name = "Lookup", Description = "Quick connect public lookup", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string Lookup { get; set; } + [ApiMember(Name = "Code", Description = "Quick connect identifying code", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Code { get; set; } } [Route("/QuickConnect/Deauthorize", "POST", Summary = "Deletes all quick connect authorization tokens for the current user")] @@ -62,8 +55,9 @@ namespace MediaBrowser.Api.QuickConnect [Route("/QuickConnect/Activate", "POST", Summary = "Temporarily activates quick connect for the time period defined in the server configuration")] [Authenticated] - public class Activate : IReturn + public class Activate : IReturn { + } public class QuickConnectService : BaseApiService @@ -96,18 +90,9 @@ namespace MediaBrowser.Api.QuickConnect return _quickConnect.CheckRequestStatus(request.Secret); } - public object Get(QuickConnectList request) - { - if(_quickConnect.State != QuickConnectState.Active) - { - return Array.Empty(); - } - - return _quickConnect.GetCurrentRequests(); - } - public object Get(QuickConnectStatus request) { + _quickConnect.ExpireRequests(); return _quickConnect.State; } @@ -120,55 +105,27 @@ namespace MediaBrowser.Api.QuickConnect public object Post(Authorize request) { - bool result = _quickConnect.AuthorizeRequest(Request, request.Lookup); - - Logger.LogInformation("Result of authorizing quick connect {0}: {1}", request.Lookup[..10], result); - - return result; + return _quickConnect.AuthorizeRequest(Request, request.Code); } public object Post(Activate request) { - string name = _authContext.GetAuthorizationInfo(Request).User.Name; - if(_quickConnect.State == QuickConnectState.Unavailable) { - return new QuickConnectResult() - { - Error = "Quick connect is not enabled on this server" - }; + return false; } - else if(_quickConnect.State == QuickConnectState.Available) - { - var result = _quickConnect.Activate(); - - if (string.IsNullOrEmpty(result.Error)) - { - Logger.LogInformation("{name} temporarily activated quick connect", name); - } + string name = _authContext.GetAuthorizationInfo(Request).User.Username; - return result; - } + Logger.LogInformation("{name} temporarily activated quick connect", name); + _quickConnect.Activate(); - else if(_quickConnect.State == QuickConnectState.Active) - { - return new QuickConnectResult() - { - Error = "" - }; - } - - return new QuickConnectResult() - { - Error = "Unknown current state" - }; + return true; } public object Post(Available request) { _quickConnect.SetEnabled(request.Status); - return _quickConnect.State; } } diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index d31d0e509..10ec9e6cb 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -38,8 +38,7 @@ namespace MediaBrowser.Controller.QuickConnect /// /// Temporarily activates quick connect for a short amount of time. /// - /// A quick connect result object indicating success. - QuickConnectResult Activate(); + void Activate(); /// /// Changes the status of quick connect. @@ -61,26 +60,20 @@ namespace MediaBrowser.Controller.QuickConnect /// Quick connect result. QuickConnectResult CheckRequestStatus(string secret); - /// - /// Returns all current quick connect requests as DTOs. Does not include sensitive information. - /// - /// List of all quick connect results. - List GetCurrentRequests(); - - /// - /// Returns all current quick connect requests (including sensitive information). - /// - /// List of all quick connect results. - List GetCurrentRequestsInternal(); - /// /// Authorizes a quick connect request to connect as the calling user. /// /// HTTP request object. - /// Identifying code for the request.. + /// Identifying code for the request. /// A boolean indicating if the authorization completed successfully. bool AuthorizeRequest(IRequest request, string code); + /// + /// Expire quick connect requests that are over the time limit. If is true, all requests are unconditionally expired. + /// + /// If true, all requests will be expired. + public void ExpireRequests(bool expireAll = false); + /// /// Deletes all quick connect access tokens for the provided user. /// diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs deleted file mode 100644 index 26084caf1..000000000 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace MediaBrowser.Model.QuickConnect -{ - /// - /// Stores the non-sensitive results of an incoming quick connect request. - /// - public class QuickConnectResultDto - { - /// - /// Gets a value indicating whether this request is authorized. - /// - public bool Authenticated { get; private set; } - - /// - /// Gets the user facing code used so the user can quickly differentiate this request from others. - /// - public string? Code { get; private set; } - - /// - /// Gets the device friendly name. - /// - public string? FriendlyName { get; private set; } - - /// - /// Cast an internal quick connect result to a DTO by removing all sensitive properties. - /// - /// QuickConnectResult object to cast. - public static implicit operator QuickConnectResultDto(QuickConnectResult result) - { - QuickConnectResultDto resultDto = new QuickConnectResultDto - { - Authenticated = result.Authenticated, - Code = result.Code, - FriendlyName = result.FriendlyName, - }; - - return resultDto; - } - } -} -- cgit v1.2.3 From 5f1a86324170387f12602d77dad7249faf30548f Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:36:45 -0500 Subject: Apply suggestions from code review --- .../QuickConnect/QuickConnectManager.cs | 38 +++++++++------------- .../Session/SessionManager.cs | 2 +- Jellyfin.Api/Controllers/QuickConnectController.cs | 34 +++++++++---------- Jellyfin.Api/Controllers/UserController.cs | 4 +-- .../QuickConnect/IQuickConnect.cs | 12 +++---- .../QuickConnect/QuickConnectResult.cs | 5 --- 6 files changed, 40 insertions(+), 55 deletions(-) (limited to 'MediaBrowser.Model/QuickConnect') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 949c3b505..52e934229 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -3,17 +3,16 @@ using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Security.Cryptography; +using MediaBrowser.Common; +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; -using Microsoft.AspNetCore.Http; -using MediaBrowser.Common; using Microsoft.Extensions.Logging; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Authentication; namespace Emby.Server.Implementations.QuickConnect { @@ -60,7 +59,7 @@ namespace Emby.Server.Implementations.QuickConnect public int CodeLength { get; set; } = 6; /// - public string TokenNamePrefix { get; set; } = "QuickConnect-"; + public string TokenName { get; set; } = "QuickConnect"; /// public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; @@ -82,7 +81,7 @@ namespace Emby.Server.Implementations.QuickConnect /// public void Activate() { - DateActivated = DateTime.Now; + DateActivated = DateTime.UtcNow; SetState(QuickConnectState.Active); } @@ -101,7 +100,7 @@ namespace Emby.Server.Implementations.QuickConnect } /// - public QuickConnectResult TryConnect(string friendlyName) + public QuickConnectResult TryConnect() { ExpireRequests(); @@ -111,14 +110,11 @@ namespace Emby.Server.Implementations.QuickConnect throw new AuthenticationException("Quick connect is not active on this server"); } - _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); - var code = GenerateCode(); var result = new QuickConnectResult() { Secret = GenerateSecureRandom(), - FriendlyName = friendlyName, - DateAdded = DateTime.Now, + DateAdded = DateTime.UtcNow, Code = code }; @@ -162,13 +158,11 @@ namespace Emby.Server.Implementations.QuickConnect } /// - public bool AuthorizeRequest(HttpRequest request, string code) + public bool AuthorizeRequest(Guid userId, string code) { ExpireRequests(); AssertActive(); - var auth = _authContext.GetAuthorizationInfo(request); - if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { throw new ResourceNotFoundException("Unable to find request"); @@ -182,21 +176,21 @@ namespace Emby.Server.Implementations.QuickConnect result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); // 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.Now.Subtract(new TimeSpan(0, Timeout, 0)); - result.DateAdded = added.Subtract(new TimeSpan(0, Timeout - 1, 0)); + var added = result.DateAdded ?? DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(Timeout)); + result.DateAdded = added.Subtract(TimeSpan.FromMinutes(Timeout - 1)); _authenticationRepository.Create(new AuthenticationInfo { - AppName = TokenNamePrefix + result.FriendlyName, + AppName = TokenName, AccessToken = result.Authentication, DateCreated = DateTime.UtcNow, DeviceId = _appHost.SystemId, DeviceName = _appHost.FriendlyName, AppVersion = _appHost.ApplicationVersionString, - UserId = auth.UserId + UserId = userId }); - _logger.LogInformation("Allowing device {FriendlyName} to login as user {Username} with quick connect code {Code}", result.FriendlyName, auth.User.Username, result.Code); + _logger.LogDebug("Authorizing device with code {Code} to login as user {userId}", code, userId); return true; } @@ -210,7 +204,7 @@ namespace Emby.Server.Implementations.QuickConnect UserId = user }); - var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenNamePrefix, StringComparison.CurrentCulture)); + var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenName, StringComparison.CurrentCulture)); var removed = 0; foreach (var token in tokens) @@ -256,7 +250,7 @@ namespace Emby.Server.Implementations.QuickConnect public void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated - if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) + if (State == QuickConnectState.Active && DateTime.UtcNow > DateActivated.AddMinutes(Timeout) && !expireAll) { _logger.LogDebug("Quick connect time expired, deactivating"); SetState(QuickConnectState.Available); @@ -270,7 +264,7 @@ namespace Emby.Server.Implementations.QuickConnect for (int i = 0; i < values.Count; i++) { var added = values[i].DateAdded ?? DateTime.UnixEpoch; - if (DateTime.Now > added.AddMinutes(Timeout) || expireAll) + if (DateTime.UtcNow > added.AddMinutes(Timeout) || expireAll) { code = values[i].Code; _logger.LogDebug("Removing expired request {code}", code); diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 8a8223ee7..fbe8e065c 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1433,7 +1433,7 @@ namespace Emby.Server.Implementations.Session Limit = 1 }); - if (result.TotalRecordCount < 1) + if (result.TotalRecordCount == 0) { throw new SecurityException("Unknown quick connect token"); } diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index 1625bcffe..b1ee2ff53 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -1,8 +1,8 @@ +using System; using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Model.QuickConnect; @@ -18,22 +18,18 @@ namespace Jellyfin.Api.Controllers public class QuickConnectController : BaseJellyfinApiController { private readonly IQuickConnect _quickConnect; - private readonly IUserManager _userManager; private readonly IAuthorizationContext _authContext; /// /// Initializes a new instance of the class. /// /// Instance of the interface. - /// Instance of the interface. /// Instance of the interface. public QuickConnectController( IQuickConnect quickConnect, - IUserManager userManager, IAuthorizationContext authContext) { _quickConnect = quickConnect; - _userManager = userManager; _authContext = authContext; } @@ -53,15 +49,14 @@ namespace Jellyfin.Api.Controllers /// /// Initiate a new quick connect request. /// - /// Device friendly name. /// Quick connect request successfully created. /// Quick connect is not active on this server. /// A with a secret and code for future use or an error message. [HttpGet("Initiate")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult Initiate([FromQuery] string? friendlyName) + public ActionResult Initiate() { - return _quickConnect.TryConnect(friendlyName); + return _quickConnect.TryConnect(); } /// @@ -74,12 +69,11 @@ namespace Jellyfin.Api.Controllers [HttpGet("Connect")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult Connect([FromQuery] string? secret) + public ActionResult Connect([FromQuery, Required] string secret) { try { - var result = _quickConnect.CheckRequestStatus(secret); - return result; + return _quickConnect.CheckRequestStatus(secret); } catch (ResourceNotFoundException) { @@ -117,9 +111,9 @@ namespace Jellyfin.Api.Controllers [HttpPost("Available")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult Available([FromQuery] QuickConnectState? status) + public ActionResult Available([FromQuery] QuickConnectState status = QuickConnectState.Available) { - _quickConnect.SetState(status ?? QuickConnectState.Available); + _quickConnect.SetState(status); return NoContent(); } @@ -127,16 +121,22 @@ namespace Jellyfin.Api.Controllers /// Authorizes a pending quick connect request. /// /// Quick connect code to authorize. + /// User id. /// Quick connect result authorized successfully. - /// Missing quick connect code. + /// User is not allowed to authorize quick connect requests. /// Boolean indicating if the authorization was successful. [HttpPost("Authorize")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - public ActionResult Authorize([FromQuery, Required] string? code) + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public ActionResult Authorize([FromQuery, Required] string code, [FromQuery, Required] Guid userId) { - return _quickConnect.AuthorizeRequest(Request, code); + if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) + { + return Forbid("User is not allowed to authorize quick connect requests."); + } + + return _quickConnect.AuthorizeRequest(userId, code); } /// diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 355816bd3..d67f82219 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -239,11 +239,9 @@ namespace Jellyfin.Api.Controllers DeviceName = auth.Device, }; - var result = await _sessionManager.AuthenticateQuickConnect( + return await _sessionManager.AuthenticateQuickConnect( authRequest, request.Token).ConfigureAwait(false); - - return result; } catch (SecurityException e) { diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index fd7e973f6..959a2d771 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -1,6 +1,5 @@ using System; using MediaBrowser.Model.QuickConnect; -using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.QuickConnect { @@ -15,9 +14,9 @@ namespace MediaBrowser.Controller.QuickConnect int CodeLength { get; set; } /// - /// Gets or sets the string to prefix internal access tokens with. + /// Gets or sets the name of internal access tokens. /// - string TokenNamePrefix { get; set; } + string TokenName { get; set; } /// /// Gets the current state of quick connect. @@ -48,9 +47,8 @@ namespace MediaBrowser.Controller.QuickConnect /// /// Initiates a new quick connect request. /// - /// Friendly device name to display in the request UI. /// A quick connect result with tokens to proceed or throws an exception if not active. - QuickConnectResult TryConnect(string friendlyName); + QuickConnectResult TryConnect(); /// /// Checks the status of an individual request. @@ -62,10 +60,10 @@ namespace MediaBrowser.Controller.QuickConnect /// /// Authorizes a quick connect request to connect as the calling user. /// - /// HTTP request object. + /// User id. /// Identifying code for the request. /// A boolean indicating if the authorization completed successfully. - bool AuthorizeRequest(HttpRequest request, string code); + bool AuthorizeRequest(Guid userId, string code); /// /// Expire quick connect requests that are over the time limit. If is true, all requests are unconditionally expired. diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs index a10d60d57..0fa40b6a7 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -22,11 +22,6 @@ namespace MediaBrowser.Model.QuickConnect /// public string? Code { get; set; } - /// - /// Gets or sets the device friendly name. - /// - public string? FriendlyName { get; set; } - /// /// Gets or sets the private access token. /// -- cgit v1.2.3