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.
This commit is contained in:
ConfusedPolarBear 2020-06-18 01:29:47 -05:00
parent 82887ec710
commit 4be476ec53
8 changed files with 41 additions and 120 deletions

View File

@ -1,20 +0,0 @@
using MediaBrowser.Common.Configuration;
namespace Emby.Server.Implementations.QuickConnect
{
/// <summary>
/// Configuration extension to support persistent quick connect configuration.
/// </summary>
public static class ConfigurationExtension
{
/// <summary>
/// Return the current quick connect configuration.
/// </summary>
/// <param name="manager">Configuration manager.</param>
/// <returns>Current quick connect configuration.</returns>
public static QuickConnectConfiguration GetQuickConnectConfiguration(this IConfigurationManager manager)
{
return manager.GetConfiguration<QuickConnectConfiguration>("quickconnect");
}
}
}

View File

@ -1,15 +0,0 @@
using MediaBrowser.Model.QuickConnect;
namespace Emby.Server.Implementations.QuickConnect
{
/// <summary>
/// Persistent quick connect configuration.
/// </summary>
public class QuickConnectConfiguration
{
/// <summary>
/// Gets or sets persistent quick connect availability state.
/// </summary>
public QuickConnectState State { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
namespace Emby.Server.Implementations.QuickConnect
{
/// <summary>
/// Configuration factory for quick connect.
/// </summary>
public class QuickConnectConfigurationFactory : IConfigurationFactory
{
/// <summary>
/// Returns the current quick connect configuration.
/// </summary>
/// <returns>Current quick connect configuration.</returns>
public IEnumerable<ConfigurationStore> GetConfigurations()
{
return new[]
{
new ConfigurationStore
{
Key = "quickconnect",
ConfigurationType = typeof(QuickConnectConfiguration)
}
};
}
}
}

View File

@ -11,7 +11,9 @@ using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Security;
using MediaBrowser.Model.QuickConnect; using MediaBrowser.Model.QuickConnect;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Common;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MediaBrowser.Common.Extensions;
namespace Emby.Server.Implementations.QuickConnect namespace Emby.Server.Implementations.QuickConnect
{ {
@ -64,9 +66,7 @@ namespace Emby.Server.Implementations.QuickConnect
public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable;
/// <inheritdoc/> /// <inheritdoc/>
public int RequestExpiry { get; set; } = 30; public int Timeout { get; set; } = 5;
private bool TemporaryActivation { get; set; } = false;
private DateTime DateActivated { get; set; } private DateTime DateActivated { get; set; }
@ -82,10 +82,9 @@ namespace Emby.Server.Implementations.QuickConnect
/// <inheritdoc/> /// <inheritdoc/>
public QuickConnectResult Activate() public QuickConnectResult Activate()
{ {
// This should not call SetEnabled since that would persist the "temporary" activation to the configuration file SetEnabled(QuickConnectState.Active);
State = QuickConnectState.Active;
DateActivated = DateTime.Now; DateActivated = DateTime.Now;
TemporaryActivation = true;
return new QuickConnectResult(); return new QuickConnectResult();
} }
@ -96,12 +95,10 @@ namespace Emby.Server.Implementations.QuickConnect
_logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState);
ExpireRequests(true); ExpireRequests(true);
State = newState;
_config.SaveConfiguration("quickconnect", new QuickConnectConfiguration() State = newState;
{ _config.Configuration.QuickConnectAvailable = newState == QuickConnectState.Available || newState == QuickConnectState.Active;
State = State _config.SaveConfiguration();
});
_logger.LogDebug("Configuration saved"); _logger.LogDebug("Configuration saved");
} }
@ -123,17 +120,16 @@ namespace Emby.Server.Implementations.QuickConnect
_logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName);
var lookup = GenerateSecureRandom(); var code = GenerateCode();
var result = new QuickConnectResult() var result = new QuickConnectResult()
{ {
Lookup = lookup,
Secret = GenerateSecureRandom(), Secret = GenerateSecureRandom(),
FriendlyName = friendlyName, FriendlyName = friendlyName,
DateAdded = DateTime.Now, DateAdded = DateTime.Now,
Code = GenerateCode() Code = code
}; };
_currentRequests[lookup] = result; _currentRequests[code] = result;
return result; return result;
} }
@ -143,17 +139,16 @@ namespace Emby.Server.Implementations.QuickConnect
ExpireRequests(); ExpireRequests();
AssertActive(); 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; return result;
} }
/// <inheritdoc/>
public List<QuickConnectResultDto> GetCurrentRequests() public List<QuickConnectResultDto> GetCurrentRequests()
{ {
return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList();
@ -186,16 +181,16 @@ namespace Emby.Server.Implementations.QuickConnect
} }
/// <inheritdoc/> /// <inheritdoc/>
public bool AuthorizeRequest(IRequest request, string lookup) public bool AuthorizeRequest(IRequest request, string code)
{ {
ExpireRequests(); ExpireRequests();
AssertActive(); AssertActive();
var auth = _authContext.GetAuthorizationInfo(request); 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) if (result.Authenticated)
@ -205,9 +200,9 @@ namespace Emby.Server.Implementations.QuickConnect
result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); 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 // 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, RequestExpiry, 0)); var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, Timeout, 0));
result.DateAdded = added.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); result.DateAdded = added.Subtract(new TimeSpan(0, Timeout - 1, 0));
_authenticationRepository.Create(new AuthenticationInfo _authenticationRepository.Create(new AuthenticationInfo
{ {
@ -271,7 +266,7 @@ namespace Emby.Server.Implementations.QuickConnect
var bytes = new byte[length]; var bytes = new byte[length];
_rng.GetBytes(bytes); _rng.GetBytes(bytes);
return string.Join(string.Empty, bytes.Select(x => x.ToString("x2", CultureInfo.InvariantCulture))); return Hex.Encode(bytes);
} }
/// <summary> /// <summary>
@ -281,12 +276,11 @@ namespace Emby.Server.Implementations.QuickConnect
private void ExpireRequests(bool expireAll = false) private void ExpireRequests(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 && !expireAll) if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll)
{ {
_logger.LogDebug("Quick connect time expired, deactivating"); _logger.LogDebug("Quick connect time expired, deactivating");
SetEnabled(QuickConnectState.Available); SetEnabled(QuickConnectState.Available);
expireAll = true; expireAll = true;
TemporaryActivation = false;
} }
// Expire stale connection requests // Expire stale connection requests
@ -296,28 +290,28 @@ namespace Emby.Server.Implementations.QuickConnect
for (int i = 0; i < values.Count; i++) for (int i = 0; i < values.Count; i++)
{ {
var added = values[i].DateAdded ?? DateTime.UnixEpoch; 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() private void ReloadConfiguration()
{ {
var config = _config.GetQuickConnectConfiguration(); var available = _config.Configuration.QuickConnectAvailable;
State = config.State; State = available ? QuickConnectState.Available : QuickConnectState.Unavailable;
} }
} }
} }

View File

@ -26,9 +26,9 @@ namespace MediaBrowser.Controller.QuickConnect
public QuickConnectState State { get; } public QuickConnectState State { get; }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public int RequestExpiry { get; set; } public int Timeout { get; set; }
/// <summary> /// <summary>
/// Assert that quick connect is currently active and throws an exception if it is not. /// 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. /// Authorizes a quick connect request to connect as the calling user.
/// </summary> /// </summary>
/// <param name="request">HTTP request object.</param> /// <param name="request">HTTP request object.</param>
/// <param name="lookup">Public request lookup value.</param> /// <param name="lookup">Identifying code for the request..</param>
/// <returns>A boolean indicating if the authorization completed successfully.</returns> /// <returns>A boolean indicating if the authorization completed successfully.</returns>
bool AuthorizeRequest(IRequest request, string lookup); bool AuthorizeRequest(IRequest request, string code);
/// <summary> /// <summary>
/// Deletes all quick connect access tokens for the provided user. /// Deletes all quick connect access tokens for the provided user.

View File

@ -76,6 +76,11 @@ namespace MediaBrowser.Model.Configuration
/// <value><c>true</c> if this instance is port authorized; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is port authorized; otherwise, <c>false</c>.</value>
public bool IsPortAuthorized { get; set; } public bool IsPortAuthorized { get; set; }
/// <summary>
/// Gets or sets if quick connect is available for use on this server.
/// </summary>
public bool QuickConnectAvailable { get; set; }
public bool AutoRunWebApp { get; set; } public bool AutoRunWebApp { get; set; }
public bool EnableRemoteAccess { get; set; } public bool EnableRemoteAccess { get; set; }
@ -281,6 +286,7 @@ namespace MediaBrowser.Model.Configuration
AutoRunWebApp = true; AutoRunWebApp = true;
EnableRemoteAccess = true; EnableRemoteAccess = true;
QuickConnectAvailable = false;
EnableUPnP = false; EnableUPnP = false;
MinResumePct = 5; MinResumePct = 5;

View File

@ -17,11 +17,6 @@ namespace MediaBrowser.Model.QuickConnect
/// </summary> /// </summary>
public string? Secret { get; set; } public string? Secret { get; set; }
/// <summary>
/// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request.
/// </summary>
public string? Lookup { get; set; }
/// <summary> /// <summary>
/// Gets or sets the user facing code used so the user can quickly differentiate this request from others. /// Gets or sets the user facing code used so the user can quickly differentiate this request from others.
/// </summary> /// </summary>

View File

@ -17,25 +17,15 @@ namespace MediaBrowser.Model.QuickConnect
/// </summary> /// </summary>
public string? Code { get; private set; } public string? Code { get; private set; }
/// <summary>
/// Gets the public value used to uniquely identify this request. Can only be used to authorize the request.
/// </summary>
public string? Lookup { get; private set; }
/// <summary> /// <summary>
/// Gets the device friendly name. /// Gets the device friendly name.
/// </summary> /// </summary>
public string? FriendlyName { get; private set; } public string? FriendlyName { get; private set; }
/// <summary>
/// Gets the DateTime that this request was created.
/// </summary>
public DateTime? DateAdded { get; private set; }
/// <summary> /// <summary>
/// Cast an internal quick connect result to a DTO by removing all sensitive properties. /// Cast an internal quick connect result to a DTO by removing all sensitive properties.
/// </summary> /// </summary>
/// <param name="result">QuickConnectResult object to cast</param> /// <param name="result">QuickConnectResult object to cast.</param>
public static implicit operator QuickConnectResultDto(QuickConnectResult result) public static implicit operator QuickConnectResultDto(QuickConnectResult result)
{ {
QuickConnectResultDto resultDto = new QuickConnectResultDto QuickConnectResultDto resultDto = new QuickConnectResultDto
@ -43,8 +33,6 @@ namespace MediaBrowser.Model.QuickConnect
Authenticated = result.Authenticated, Authenticated = result.Authenticated,
Code = result.Code, Code = result.Code,
FriendlyName = result.FriendlyName, FriendlyName = result.FriendlyName,
DateAdded = result.DateAdded,
Lookup = result.Lookup
}; };
return resultDto; return resultDto;