From a3e08c91605d2bc32a61ce4e33263c25d47102bd Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 26 Apr 2018 20:56:19 -0400 Subject: [PATCH] Fixed: Setup remote access for service during install Co-Authored-By: Mark McDowall --- setup/lidarr.iss | 9 ++-- src/NzbDrone.Common/ConsoleService.cs | 8 +++- .../EnvironmentInfo/StartupContext.cs | 10 ++-- src/NzbDrone.Console/ConsoleApp.cs | 8 ++++ .../AccessControl/RemoteAccessAdapter.cs | 46 +++++++++++++++++++ .../AccessControl/RemoteAccessException.cs | 24 ++++++++++ src/NzbDrone.Host/ApplicationModes.cs | 3 +- src/NzbDrone.Host/Bootstrap.cs | 8 +++- src/NzbDrone.Host/NzbDrone.Host.csproj | 2 + src/NzbDrone.Host/Owin/OwinHostController.cs | 25 ++-------- src/NzbDrone.Host/Router.cs | 12 +++++ 11 files changed, 124 insertions(+), 31 deletions(-) create mode 100644 src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs create mode 100644 src/NzbDrone.Host/AccessControl/RemoteAccessException.cs diff --git a/setup/lidarr.iss b/setup/lidarr.iss index e64f923a0..bfefa210f 100644 --- a/setup/lidarr.iss +++ b/setup/lidarr.iss @@ -17,7 +17,7 @@ ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{56C1065D-3523-4025-B76D-6F73F67F7F93} AppName={#AppName} -AppVersion=2.0 +AppVersion=0.3 AppPublisher={#AppPublisher} AppPublisherURL={#AppURL} AppSupportURL={#ForumsURL} @@ -57,9 +57,10 @@ Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: Name: "{userstartup}\{#AppName}"; Filename: "{app}\Lidarr.exe"; WorkingDir: "{app}"; Tasks: startupShortcut [Run] -Filename: "{app}\Lidarr.Console.exe"; Parameters: "/u"; Flags: runhidden waituntilterminated; -Filename: "{app}\Lidarr.Console.exe"; Parameters: "/i"; Flags: runhidden waituntilterminated; Tasks: windowsService -Filename: "{app}\Lidarr.exe"; Description: "Open Lidarr"; Flags: postinstall skipifsilent nowait; Tasks: windowsService; +Filename: "{app}\Lidarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u"; Flags: runhidden waituntilterminated; +Filename: "{app}\Lidarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none; +Filename: "{app}\Lidarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i"; Flags: runhidden waituntilterminated; Tasks: windowsService +Filename: "{app}\Lidarr.exe"; Description: "Open Lidarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService; Filename: "{app}\Lidarr.exe"; Description: "Start Lidarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none; [UninstallRun] diff --git a/src/NzbDrone.Common/ConsoleService.cs b/src/NzbDrone.Common/ConsoleService.cs index 7801b21bc..e44dfcf52 100644 --- a/src/NzbDrone.Common/ConsoleService.cs +++ b/src/NzbDrone.Common/ConsoleService.cs @@ -21,8 +21,12 @@ namespace NzbDrone.Common Console.WriteLine(); Console.WriteLine(" Usage: {0} ", Process.GetCurrentProcess().MainModule.ModuleName); Console.WriteLine(" Commands:"); - Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.SERVICE_NAME); - Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.SERVICE_NAME); + if (OsInfo.IsWindows) + { + Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.SERVICE_NAME); + Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.SERVICE_NAME); + Console.WriteLine(" /{0} Register URL and open firewall port (allows access from other devices on your network).", StartupContext.REGISTER_URL); + } Console.WriteLine(" /{0} Don't open Lidarr in a browser", StartupContext.NO_BROWSER); Console.WriteLine(" /{0} Start Lidarr terminating any other instances", StartupContext.TERMINATE); Console.WriteLine(" /{0}=path Path to use as the AppData location (stores database, config, logs, etc)", StartupContext.APPDATA); diff --git a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs index 49925b415..62c3f7787 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace NzbDrone.Common.EnvironmentInfo { @@ -6,8 +6,10 @@ namespace NzbDrone.Common.EnvironmentInfo { HashSet Flags { get; } Dictionary Args { get; } + bool Help { get; } bool InstallService { get; } bool UninstallService { get; } + bool RegisterUrl { get; } string PreservedArguments { get; } } @@ -21,6 +23,7 @@ namespace NzbDrone.Common.EnvironmentInfo public const string HELP = "?"; public const string TERMINATE = "terminateexisting"; public const string RESTART = "restart"; + public const string REGISTER_URL = "registerurl"; public StartupContext(params string[] args) { @@ -47,9 +50,10 @@ namespace NzbDrone.Common.EnvironmentInfo public HashSet Flags { get; private set; } public Dictionary Args { get; private set; } + public bool Help => Flags.Contains(HELP); public bool InstallService => Flags.Contains(INSTALL_SERVICE); - public bool UninstallService => Flags.Contains(UNINSTALL_SERVICE); + public bool RegisterUrl => Flags.Contains(REGISTER_URL); public string PreservedArguments { @@ -71,4 +75,4 @@ namespace NzbDrone.Common.EnvironmentInfo } } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Console/ConsoleApp.cs b/src/NzbDrone.Console/ConsoleApp.cs index b4a97b29c..54e12655a 100644 --- a/src/NzbDrone.Console/ConsoleApp.cs +++ b/src/NzbDrone.Console/ConsoleApp.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Host; +using NzbDrone.Host.AccessControl; namespace NzbDrone.Console { @@ -50,6 +51,13 @@ namespace NzbDrone.Console Logger.Fatal(ex.Message + ". This can happen if another instance of Lidarr is already running another application is using the same port (default: 8686) or the user has insufficient permissions"); Exit(ExitCodes.RecoverableFailure); } + catch (RemoteAccessException ex) + { + System.Console.WriteLine(""); + System.Console.WriteLine(""); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.Normal); + } catch (Exception ex) { System.Console.WriteLine(""); diff --git a/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs b/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs new file mode 100644 index 000000000..5a4aaa024 --- /dev/null +++ b/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs @@ -0,0 +1,46 @@ +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Host.AccessControl +{ + public interface IRemoteAccessAdapter + { + void MakeAccessible(bool passive); + } + + public class RemoteAccessAdapter : IRemoteAccessAdapter + { + private readonly IRuntimeInfo _runtimeInfo; + private readonly IUrlAclAdapter _urlAclAdapter; + private readonly IFirewallAdapter _firewallAdapter; + private readonly ISslAdapter _sslAdapter; + + public RemoteAccessAdapter(IRuntimeInfo runtimeInfo, + IUrlAclAdapter urlAclAdapter, + IFirewallAdapter firewallAdapter, + ISslAdapter sslAdapter) + { + _runtimeInfo = runtimeInfo; + _urlAclAdapter = urlAclAdapter; + _firewallAdapter = firewallAdapter; + _sslAdapter = sslAdapter; + } + + public void MakeAccessible(bool passive) + { + if (OsInfo.IsWindows) + { + if (_runtimeInfo.IsAdmin) + { + _firewallAdapter.MakeAccessible(); + _sslAdapter.Register(); + } + else if (!passive) + { + throw new RemoteAccessException("Failed to register URLs for Sonarr. Sonarr will not be accessible remotely"); + } + } + + _urlAclAdapter.ConfigureUrls(); + } + } +} diff --git a/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs b/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs new file mode 100644 index 000000000..abd481040 --- /dev/null +++ b/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs @@ -0,0 +1,24 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Host.AccessControl +{ + public class RemoteAccessException : NzbDroneException + { + public RemoteAccessException(string message, params object[] args) : base(message, args) + { + } + + public RemoteAccessException(string message) : base(message) + { + } + + public RemoteAccessException(string message, Exception innerException, params object[] args) : base(message, innerException, args) + { + } + + public RemoteAccessException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/src/NzbDrone.Host/ApplicationModes.cs b/src/NzbDrone.Host/ApplicationModes.cs index aa425948c..ec06ea1f3 100644 --- a/src/NzbDrone.Host/ApplicationModes.cs +++ b/src/NzbDrone.Host/ApplicationModes.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Host +namespace NzbDrone.Host { public enum ApplicationModes { @@ -7,5 +7,6 @@ InstallService, UninstallService, Service, + RegisterUrl } } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 69c15dd16..e5b6e8413 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -112,11 +112,16 @@ namespace NzbDrone.Host private static ApplicationModes GetApplicationMode(IStartupContext startupContext) { - if (startupContext.Flags.Contains(StartupContext.HELP)) + if (startupContext.Help) { return ApplicationModes.Help; } + if (OsInfo.IsWindows && startupContext.RegisterUrl) + { + return ApplicationModes.RegisterUrl; + } + if (OsInfo.IsWindows && startupContext.InstallService) { return ApplicationModes.InstallService; @@ -141,6 +146,7 @@ namespace NzbDrone.Host { case ApplicationModes.InstallService: case ApplicationModes.UninstallService: + case ApplicationModes.RegisterUrl: case ApplicationModes.Help: { return true; diff --git a/src/NzbDrone.Host/NzbDrone.Host.csproj b/src/NzbDrone.Host/NzbDrone.Host.csproj index efae82ab7..e705fdc02 100644 --- a/src/NzbDrone.Host/NzbDrone.Host.csproj +++ b/src/NzbDrone.Host/NzbDrone.Host.csproj @@ -112,6 +112,8 @@ + + diff --git a/src/NzbDrone.Host/Owin/OwinHostController.cs b/src/NzbDrone.Host/Owin/OwinHostController.cs index 82357c24c..feecd39d2 100644 --- a/src/NzbDrone.Host/Owin/OwinHostController.cs +++ b/src/NzbDrone.Host/Owin/OwinHostController.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Host.Owin public class OwinHostController : IHostController { private readonly IOwinAppFactory _owinAppFactory; - private readonly IRuntimeInfo _runtimeInfo; + private readonly IRemoteAccessAdapter _removeAccessAdapter; private readonly IUrlAclAdapter _urlAclAdapter; private readonly IFirewallAdapter _firewallAdapter; private readonly ISslAdapter _sslAdapter; @@ -17,32 +17,21 @@ namespace NzbDrone.Host.Owin public OwinHostController( IOwinAppFactory owinAppFactory, - IRuntimeInfo runtimeInfo, + IRemoteAccessAdapter removeAccessAdapter, IUrlAclAdapter urlAclAdapter, IFirewallAdapter firewallAdapter, ISslAdapter sslAdapter, Logger logger) { _owinAppFactory = owinAppFactory; - _runtimeInfo = runtimeInfo; + _removeAccessAdapter = removeAccessAdapter; _urlAclAdapter = urlAclAdapter; - _firewallAdapter = firewallAdapter; - _sslAdapter = sslAdapter; _logger = logger; } public void StartServer() { - if (OsInfo.IsWindows) - { - if (_runtimeInfo.IsAdmin) - { - _firewallAdapter.MakeAccessible(); - _sslAdapter.Register(); - } - } - - _urlAclAdapter.ConfigureUrls(); + _removeAccessAdapter.MakeAccessible(true); _logger.Info("Listening on the following URLs:"); foreach (var url in _urlAclAdapter.Urls) @@ -53,7 +42,6 @@ namespace NzbDrone.Host.Owin _owinApp = _owinAppFactory.CreateApp(_urlAclAdapter.Urls); } - public void StopServer() { if (_owinApp == null) return; @@ -63,8 +51,5 @@ namespace NzbDrone.Host.Owin _owinApp = null; _logger.Info("Host has stopped"); } - - - } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Host/Router.cs b/src/NzbDrone.Host/Router.cs index 93d785d6e..e6dd1c6f0 100644 --- a/src/NzbDrone.Host/Router.cs +++ b/src/NzbDrone.Host/Router.cs @@ -3,6 +3,7 @@ using NLog; using NzbDrone.Common; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Processes; +using NzbDrone.Host.AccessControl; using IServiceProvider = NzbDrone.Common.IServiceProvider; @@ -15,6 +16,7 @@ namespace NzbDrone.Host private readonly IConsoleService _consoleService; private readonly IRuntimeInfo _runtimeInfo; private readonly IProcessProvider _processProvider; + private readonly IRemoteAccessAdapter _remoteAccessAdapter; private readonly Logger _logger; public Router(INzbDroneServiceFactory nzbDroneServiceFactory, @@ -22,6 +24,7 @@ namespace NzbDrone.Host IConsoleService consoleService, IRuntimeInfo runtimeInfo, IProcessProvider processProvider, + IRemoteAccessAdapter remoteAccessAdapter, Logger logger) { _nzbDroneServiceFactory = nzbDroneServiceFactory; @@ -29,6 +32,7 @@ namespace NzbDrone.Host _consoleService = consoleService; _runtimeInfo = runtimeInfo; _processProvider = processProvider; + _remoteAccessAdapter = remoteAccessAdapter; _logger = logger; } @@ -60,6 +64,7 @@ namespace NzbDrone.Host } else { + _remoteAccessAdapter.MakeAccessible(true); _serviceProvider.Install(ServiceProvider.SERVICE_NAME); _serviceProvider.SetPermissions(ServiceProvider.SERVICE_NAME); @@ -81,6 +86,13 @@ namespace NzbDrone.Host _serviceProvider.Uninstall(ServiceProvider.SERVICE_NAME); } + break; + } + case ApplicationModes.RegisterUrl: + { + _logger.Debug("Regiser URL selected"); + _remoteAccessAdapter.MakeAccessible(false); + break; } default: