mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-05 02:22:31 +01:00
Proxy Support for Sonarr #732
Switch to use Port #0 which just uses the next free port Non Functional - Code Cleanup Tabs -> Spaces, Opps Deleted too much Refactoring & Code Cleanup & Move Config to DB remove unneeded line Clean Up Spaces Code Review Points on the UI FIx extra space Clean Up unrequired changes Add a HealthCheck. Extra Check in ProxyCheck. Correctly deal with Socks Authentication Remove SubModule Add in Nuget + Tweak ProxyCheck Code Review Points Missed Review Point Add Subnet Filtering, Add ProxyBypass for local addresses. UI updated for property changes. Fix typo, and copy&paste error Tweak URL to hit
This commit is contained in:
parent
7284ef50eb
commit
bfe134ee54
@ -15,12 +15,14 @@ namespace NzbDrone.Api.Config
|
|||||||
public class HostConfigModule : NzbDroneRestModule<HostConfigResource>
|
public class HostConfigModule : NzbDroneRestModule<HostConfigResource>
|
||||||
{
|
{
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
public HostConfigModule(IConfigFileProvider configFileProvider, IUserService userService)
|
public HostConfigModule(IConfigFileProvider configFileProvider, IConfigService configService, IUserService userService)
|
||||||
: base("/config/host")
|
: base("/config/host")
|
||||||
{
|
{
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
|
_configService = configService;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
|
||||||
GetResourceSingle = GetHostConfig;
|
GetResourceSingle = GetHostConfig;
|
||||||
@ -49,7 +51,7 @@ public HostConfigModule(IConfigFileProvider configFileProvider, IUserService use
|
|||||||
private HostConfigResource GetHostConfig()
|
private HostConfigResource GetHostConfig()
|
||||||
{
|
{
|
||||||
var resource = new HostConfigResource();
|
var resource = new HostConfigResource();
|
||||||
resource.InjectFrom(_configFileProvider);
|
resource.InjectFrom(_configFileProvider, _configService);
|
||||||
resource.Id = 1;
|
resource.Id = 1;
|
||||||
|
|
||||||
var user = _userService.FindUser();
|
var user = _userService.FindUser();
|
||||||
@ -75,6 +77,7 @@ private void SaveHostConfig(HostConfigResource resource)
|
|||||||
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
||||||
|
|
||||||
_configFileProvider.SaveConfigDictionary(dictionary);
|
_configFileProvider.SaveConfigDictionary(dictionary);
|
||||||
|
_configService.SaveConfigDictionary(dictionary);
|
||||||
|
|
||||||
if (resource.Username.IsNotNullOrWhiteSpace() && resource.Password.IsNotNullOrWhiteSpace())
|
if (resource.Username.IsNotNullOrWhiteSpace() && resource.Password.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Core.Authentication;
|
using NzbDrone.Core.Authentication;
|
||||||
using NzbDrone.Core.Update;
|
using NzbDrone.Core.Update;
|
||||||
|
using NzbDrone.Core.Http;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Config
|
namespace NzbDrone.Api.Config
|
||||||
{
|
{
|
||||||
@ -25,5 +27,13 @@ public class HostConfigResource : RestResource
|
|||||||
public bool UpdateAutomatically { get; set; }
|
public bool UpdateAutomatically { get; set; }
|
||||||
public UpdateMechanism UpdateMechanism { get; set; }
|
public UpdateMechanism UpdateMechanism { get; set; }
|
||||||
public string UpdateScriptPath { get; set; }
|
public string UpdateScriptPath { get; set; }
|
||||||
|
public bool ProxyEnabled { get; set; }
|
||||||
|
public ProxyType ProxyType { get; set; }
|
||||||
|
public string ProxyHostname { get; set; }
|
||||||
|
public int ProxyPort { get; set; }
|
||||||
|
public string ProxyUsername { get; set; }
|
||||||
|
public string ProxyPassword { get; set; }
|
||||||
|
public string ProxySubnetFilter { get; set; }
|
||||||
|
public bool ProxyBypassLocalAddresses { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,32 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
|||||||
return s * n;
|
return s * n;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(request.Proxy != null && !request.Proxy.ShouldProxyBeBypassed(request.Url))
|
||||||
|
|
||||||
|
{
|
||||||
|
switch (request.Proxy.Type)
|
||||||
|
{
|
||||||
|
case ProxyType.Http:
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Http);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyAuth, CurlHttpAuth.Basic);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyUserPwd, request.Proxy.Username + ":" + request.Proxy.Password.ToString());
|
||||||
|
break;
|
||||||
|
case ProxyType.Socks4:
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Socks4);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyUsername, request.Proxy.Username);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyPassword, request.Proxy.Password);
|
||||||
|
break;
|
||||||
|
case ProxyType.Socks5:
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Socks5);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyUsername, request.Proxy.Username);
|
||||||
|
curlEasy.SetOpt(CurlOption.ProxyPassword, request.Proxy.Password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curlEasy.SetOpt(CurlOption.Proxy, request.Proxy.Host + ":" + request.Proxy.Port.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
curlEasy.Url = request.Url.FullUri;
|
curlEasy.Url = request.Url.FullUri;
|
||||||
|
|
||||||
switch (request.Method)
|
switch (request.Method)
|
||||||
{
|
{
|
||||||
case HttpMethod.GET:
|
case HttpMethod.GET:
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using com.LandonKey.SocksWebProxy.Proxy;
|
||||||
|
using com.LandonKey.SocksWebProxy;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Http.Dispatchers
|
namespace NzbDrone.Common.Http.Dispatchers
|
||||||
{
|
{
|
||||||
@ -26,6 +29,33 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
|||||||
webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds);
|
webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.Proxy != null && !request.Proxy.ShouldProxyBeBypassed(request.Url))
|
||||||
|
{
|
||||||
|
var addresses = Dns.GetHostAddresses(request.Proxy.Host);
|
||||||
|
var socksUsername = request.Proxy.Username == null ? string.Empty : request.Proxy.Username;
|
||||||
|
var socksPassword = request.Proxy.Password == null ? string.Empty : request.Proxy.Password;
|
||||||
|
|
||||||
|
switch (request.Proxy.Type)
|
||||||
|
{
|
||||||
|
case ProxyType.Http:
|
||||||
|
if(request.Proxy.Username.IsNotNullOrWhiteSpace() && request.Proxy.Password.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
webRequest.Proxy = new WebProxy(request.Proxy.Host + ":" + request.Proxy.Port, request.Proxy.BypassLocalAddress, request.Proxy.SubnetFilterAsArray, new NetworkCredential(request.Proxy.Username, request.Proxy.Password));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
webRequest.Proxy = new WebProxy(request.Proxy.Host + ":" + request.Proxy.Port, request.Proxy.BypassLocalAddress, request.Proxy.SubnetFilterAsArray);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProxyType.Socks4:
|
||||||
|
webRequest.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Parse("127.0.0.1"), GetNextFreePort(), addresses[0], request.Proxy.Port, ProxyConfig.SocksVersion.Four, socksUsername, socksPassword), false);
|
||||||
|
break;
|
||||||
|
case ProxyType.Socks5:
|
||||||
|
webRequest.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Parse("127.0.0.1"), GetNextFreePort(), addresses[0], request.Proxy.Port, ProxyConfig.SocksVersion.Five, socksUsername, socksPassword), false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (request.Headers != null)
|
if (request.Headers != null)
|
||||||
{
|
{
|
||||||
AddRequestHeaders(webRequest, request.Headers);
|
AddRequestHeaders(webRequest, request.Headers);
|
||||||
@ -117,5 +147,15 @@ protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader h
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetNextFreePort()
|
||||||
|
{
|
||||||
|
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||||
|
listener.Start();
|
||||||
|
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||||
|
listener.Stop();
|
||||||
|
|
||||||
|
return port;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public HttpRequest(string url, HttpAccept httpAccept = null)
|
|||||||
Headers = new HttpHeader();
|
Headers = new HttpHeader();
|
||||||
AllowAutoRedirect = true;
|
AllowAutoRedirect = true;
|
||||||
Cookies = new Dictionary<string, string>();
|
Cookies = new Dictionary<string, string>();
|
||||||
|
|
||||||
if (!RuntimeInfoBase.IsProduction)
|
if (!RuntimeInfoBase.IsProduction)
|
||||||
{
|
{
|
||||||
AllowAutoRedirect = false;
|
AllowAutoRedirect = false;
|
||||||
@ -41,6 +41,7 @@ public HttpRequest(string url, HttpAccept httpAccept = null)
|
|||||||
public bool StoreResponseCookie { get; set; }
|
public bool StoreResponseCookie { get; set; }
|
||||||
public TimeSpan RequestTimeout { get; set; }
|
public TimeSpan RequestTimeout { get; set; }
|
||||||
public TimeSpan RateLimit { get; set; }
|
public TimeSpan RateLimit { get; set; }
|
||||||
|
public HttpRequestProxySettings Proxy {get; set;}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
45
src/NzbDrone.Common/Http/HttpRequestProxySettings.cs
Normal file
45
src/NzbDrone.Common/Http/HttpRequestProxySettings.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Http
|
||||||
|
{
|
||||||
|
public class HttpRequestProxySettings
|
||||||
|
{
|
||||||
|
public HttpRequestProxySettings(ProxyType type, string host, int port, string filterSubnet, bool bypassLocalAddress, string username = null, string password = null)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Host = host;
|
||||||
|
Port = port;
|
||||||
|
Username = username;
|
||||||
|
Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyType Type { get; private set; }
|
||||||
|
public string Host { get; private set; }
|
||||||
|
public int Port { get; private set; }
|
||||||
|
public string Username { get; private set; }
|
||||||
|
public string Password { get; private set; }
|
||||||
|
public string SubnetFilter { get; private set; }
|
||||||
|
public bool BypassLocalAddress { get; private set; }
|
||||||
|
|
||||||
|
public string[] SubnetFilterAsArray
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(SubnetFilter))
|
||||||
|
{
|
||||||
|
return SubnetFilter.Split(';');
|
||||||
|
}
|
||||||
|
return new string[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldProxyBeBypassed(Uri url)
|
||||||
|
{
|
||||||
|
//We are utilising the WebProxy implementation here to save us having to reimplement it. This way we use Microsofts implementation
|
||||||
|
WebProxy proxy = new WebProxy(Host + ":" + Port, BypassLocalAddress, SubnetFilterAsArray);
|
||||||
|
|
||||||
|
return proxy.IsBypassed(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/NzbDrone.Common/Http/ProxyType.cs
Normal file
14
src/NzbDrone.Common/Http/ProxyType.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Http
|
||||||
|
{
|
||||||
|
public enum ProxyType
|
||||||
|
{
|
||||||
|
Http,
|
||||||
|
Socks4,
|
||||||
|
Socks5
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,12 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.3.0-rc1\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.3.0-rc1\lib\net40\NLog.dll</HintPath>
|
||||||
|
<Reference Include="Org.Mentalis, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\DotNet4.SocksProxy.1.0.0.0\lib\net40\Org.Mentalis.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SocksWebProxy, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\DotNet4.SocksProxy.1.0.0.0\lib\net40\SocksWebProxy.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
@ -161,6 +167,7 @@
|
|||||||
<Compile Include="Http\HttpMethod.cs" />
|
<Compile Include="Http\HttpMethod.cs" />
|
||||||
<Compile Include="Http\HttpProvider.cs" />
|
<Compile Include="Http\HttpProvider.cs" />
|
||||||
<Compile Include="Http\HttpRequest.cs" />
|
<Compile Include="Http\HttpRequest.cs" />
|
||||||
|
<Compile Include="Http\HttpRequestProxySettings.cs" />
|
||||||
<Compile Include="Http\HttpResponse.cs" />
|
<Compile Include="Http\HttpResponse.cs" />
|
||||||
<Compile Include="Http\HttpUri.cs" />
|
<Compile Include="Http\HttpUri.cs" />
|
||||||
<Compile Include="Http\IHttpRequestInterceptor.cs" />
|
<Compile Include="Http\IHttpRequestInterceptor.cs" />
|
||||||
@ -171,6 +178,7 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Http\HttpRequestBuilder.cs" />
|
<Compile Include="Http\HttpRequestBuilder.cs" />
|
||||||
<Compile Include="Http\HttpRequestBuilderFactory.cs" />
|
<Compile Include="Http\HttpRequestBuilderFactory.cs" />
|
||||||
|
<Compile Include="Http\ProxyType.cs" />
|
||||||
<Compile Include="Http\TooManyRequestsException.cs" />
|
<Compile Include="Http\TooManyRequestsException.cs" />
|
||||||
<Compile Include="Extensions\IEnumerableExtensions.cs" />
|
<Compile Include="Extensions\IEnumerableExtensions.cs" />
|
||||||
<Compile Include="Http\UserAgentBuilder.cs" />
|
<Compile Include="Http\UserAgentBuilder.cs" />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="DotNet4.SocksProxy" version="1.0.0.0" targetFramework="net40" />
|
||||||
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
|
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.3.0-rc1" targetFramework="net40" />
|
<package id="NLog" version="4.3.0-rc1" targetFramework="net40" />
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Update;
|
using NzbDrone.Core.Update;
|
||||||
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Configuration
|
namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
public interface IConfigFileProvider : IHandleAsync<ApplicationStartedEvent>,
|
public interface IConfigFileProvider : IHandleAsync<ApplicationStartedEvent>,
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
using NzbDrone.Core.Configuration.Events;
|
using NzbDrone.Core.Configuration.Events;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Http;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Configuration
|
namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
@ -312,6 +314,46 @@ public string HmacSalt
|
|||||||
get { return GetValue("HmacSalt", Guid.NewGuid().ToString(), true); }
|
get { return GetValue("HmacSalt", Guid.NewGuid().ToString(), true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ProxyEnabled
|
||||||
|
{
|
||||||
|
get { return GetValueBoolean("ProxyEnabled", false); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyType ProxyType
|
||||||
|
{
|
||||||
|
get { return GetValueEnum<ProxyType>("ProxyType", ProxyType.Http); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProxyHostname
|
||||||
|
{
|
||||||
|
get { return GetValue("ProxyHostname", string.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ProxyPort
|
||||||
|
{
|
||||||
|
get { return GetValueInt("ProxyPort", 8080); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProxyUsername
|
||||||
|
{
|
||||||
|
get { return GetValue("ProxyUsername", string.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProxyPassword
|
||||||
|
{
|
||||||
|
get { return GetValue("ProxyPassword", string.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProxySubnetFilter
|
||||||
|
{
|
||||||
|
get { return GetValue("ProxySubnetFilter", string.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ProxyBypassLocalAddresses
|
||||||
|
{
|
||||||
|
get { return GetValueBoolean("ProxyBypassLocalAddresses", true); }
|
||||||
|
}
|
||||||
|
|
||||||
private string GetValue(string key)
|
private string GetValue(string key)
|
||||||
{
|
{
|
||||||
return GetValue(key, string.Empty);
|
return GetValue(key, string.Empty);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Http;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Configuration
|
namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
@ -64,5 +66,15 @@ public interface IConfigService
|
|||||||
string HmacPassphrase { get; }
|
string HmacPassphrase { get; }
|
||||||
string RijndaelSalt { get; }
|
string RijndaelSalt { get; }
|
||||||
string HmacSalt { get; }
|
string HmacSalt { get; }
|
||||||
|
|
||||||
|
//Proxy
|
||||||
|
bool ProxyEnabled { get; }
|
||||||
|
ProxyType ProxyType { get; }
|
||||||
|
string ProxyHostname { get; }
|
||||||
|
int ProxyPort { get; }
|
||||||
|
string ProxyUsername { get; }
|
||||||
|
string ProxyPassword { get; }
|
||||||
|
string ProxySubnetFilter { get; }
|
||||||
|
bool ProxyBypassLocalAddresses { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs
Normal file
58
src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
|
{
|
||||||
|
public class ProxyCheck : HealthCheckBase
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
private readonly IHttpClient _client;
|
||||||
|
|
||||||
|
public ProxyCheck(IConfigService configService, IHttpClient client, Logger logger)
|
||||||
|
{
|
||||||
|
_configService = configService;
|
||||||
|
_client = client;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override HealthCheck Check()
|
||||||
|
{
|
||||||
|
if (_configService.ProxyEnabled)
|
||||||
|
{
|
||||||
|
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
|
||||||
|
if(addresses.Length != 1)
|
||||||
|
{
|
||||||
|
return new HealthCheck(GetType(), HealthCheckResult.Error, "Failed to resolve the IP Address for the Configured Proxy Host: " + _configService.ProxyHostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new HttpRequestBuilder("https://services.sonarr.tv/").Build("/ping");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = _client.Execute(request);
|
||||||
|
|
||||||
|
// We only care about 400 responses, other error codes can be ignored
|
||||||
|
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||||
|
{
|
||||||
|
_logger.Error("Proxy Health Check failed: {0}. Response Data: {1} ", response.StatusCode.ToString(), response.ResponseData);
|
||||||
|
return new HealthCheck(GetType(), HealthCheckResult.Error, "Failed to load https://sonarr.tv/, got HTTP " + response.StatusCode.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Proxy Health Check failed.", ex);
|
||||||
|
return new HealthCheck(GetType(), HealthCheckResult.Error, "An exception occured while trying to load https://sonarr.tv/: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HealthCheck(GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/NzbDrone.Core/Http/ProxyHttpInterceptor.cs
Normal file
40
src/NzbDrone.Core/Http/ProxyHttpInterceptor.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Http
|
||||||
|
{
|
||||||
|
public class ProxyHttpInterceptor : IHttpRequestInterceptor
|
||||||
|
{
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
|
||||||
|
public ProxyHttpInterceptor(IConfigService configService)
|
||||||
|
{
|
||||||
|
this._configService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse PostResponse(HttpResponse response)
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest PreRequest(HttpRequest request)
|
||||||
|
{
|
||||||
|
if(_configService.ProxyEnabled)
|
||||||
|
{
|
||||||
|
request.Proxy = new HttpRequestProxySettings(_configService.ProxyType,
|
||||||
|
_configService.ProxyHostname,
|
||||||
|
_configService.ProxyPort,
|
||||||
|
_configService.ProxySubnetFilter,
|
||||||
|
_configService.ProxyBypassLocalAddresses,
|
||||||
|
_configService.ProxyUsername,
|
||||||
|
_configService.ProxyPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -487,6 +487,7 @@
|
|||||||
<Compile Include="HealthCheck\Checks\IndexerCheck.cs" />
|
<Compile Include="HealthCheck\Checks\IndexerCheck.cs" />
|
||||||
<Compile Include="HealthCheck\Checks\MediaInfoDllCheck.cs" />
|
<Compile Include="HealthCheck\Checks\MediaInfoDllCheck.cs" />
|
||||||
<Compile Include="HealthCheck\Checks\MonoVersionCheck.cs" />
|
<Compile Include="HealthCheck\Checks\MonoVersionCheck.cs" />
|
||||||
|
<Compile Include="HealthCheck\Checks\ProxyCheck.cs" />
|
||||||
<Compile Include="HealthCheck\Checks\RootFolderCheck.cs" />
|
<Compile Include="HealthCheck\Checks\RootFolderCheck.cs" />
|
||||||
<Compile Include="HealthCheck\Checks\UpdateCheck.cs" />
|
<Compile Include="HealthCheck\Checks\UpdateCheck.cs" />
|
||||||
<Compile Include="HealthCheck\HealthCheck.cs" />
|
<Compile Include="HealthCheck\HealthCheck.cs" />
|
||||||
@ -514,6 +515,7 @@
|
|||||||
<Compile Include="Housekeeping\HousekeepingCommand.cs" />
|
<Compile Include="Housekeeping\HousekeepingCommand.cs" />
|
||||||
<Compile Include="Housekeeping\HousekeepingService.cs" />
|
<Compile Include="Housekeeping\HousekeepingService.cs" />
|
||||||
<Compile Include="Housekeeping\IHousekeepingTask.cs" />
|
<Compile Include="Housekeeping\IHousekeepingTask.cs" />
|
||||||
|
<Compile Include="Http\ProxyHttpInterceptor.cs" />
|
||||||
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
|
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
|
||||||
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
|
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
|
||||||
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
|
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
|
||||||
|
@ -11,6 +11,7 @@ var view = Marionette.ItemView.extend({
|
|||||||
|
|
||||||
events : {
|
events : {
|
||||||
'change .x-auth' : '_setAuthOptionsVisibility',
|
'change .x-auth' : '_setAuthOptionsVisibility',
|
||||||
|
'change .x-proxy' : '_setProxyOptionsVisibility',
|
||||||
'change .x-ssl' : '_setSslOptionsVisibility',
|
'change .x-ssl' : '_setSslOptionsVisibility',
|
||||||
'click .x-reset-api-key' : '_resetApiKey',
|
'click .x-reset-api-key' : '_resetApiKey',
|
||||||
'change .x-update-mechanism' : '_setScriptGroupVisibility'
|
'change .x-update-mechanism' : '_setScriptGroupVisibility'
|
||||||
@ -25,7 +26,9 @@ var view = Marionette.ItemView.extend({
|
|||||||
copyApiKey : '.x-copy-api-key',
|
copyApiKey : '.x-copy-api-key',
|
||||||
apiKeyInput : '.x-api-key',
|
apiKeyInput : '.x-api-key',
|
||||||
updateMechanism : '.x-update-mechanism',
|
updateMechanism : '.x-update-mechanism',
|
||||||
scriptGroup : '.x-script-group'
|
scriptGroup : '.x-script-group',
|
||||||
|
proxyToggle : '.x-proxy',
|
||||||
|
proxyOptions : '.x-proxy-settings'
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
@ -37,6 +40,10 @@ var view = Marionette.ItemView.extend({
|
|||||||
this.ui.authOptions.hide();
|
this.ui.authOptions.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.ui.proxyToggle.prop('checked')) {
|
||||||
|
this.ui.proxyOptions.hide();
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.ui.sslToggle.prop('checked')) {
|
if (!this.ui.sslToggle.prop('checked')) {
|
||||||
this.ui.sslOptions.hide();
|
this.ui.sslOptions.hide();
|
||||||
}
|
}
|
||||||
@ -70,6 +77,15 @@ var view = Marionette.ItemView.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setProxyOptionsVisibility : function() {
|
||||||
|
if (this.ui.proxyToggle.prop('checked')) {
|
||||||
|
this.ui.proxyOptions.slideDown();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.ui.proxyOptions.slideUp();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_setSslOptionsVisibility : function() {
|
_setSslOptionsVisibility : function() {
|
||||||
|
|
||||||
var showSslOptions = this.ui.sslToggle.prop('checked');
|
var showSslOptions = this.ui.sslToggle.prop('checked');
|
||||||
|
@ -162,6 +162,114 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Proxy Settings</legend>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Use Proxy</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<label class="checkbox toggle well">
|
||||||
|
<input type="checkbox" name="proxyEnabled" class="form-control x-proxy"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span>Yes</span>
|
||||||
|
<span>No</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="btn btn-primary slide-button"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="x-proxy-settings">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Proxy Type</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select name="proxyType" class="form-control">
|
||||||
|
<option value="http" selected="selected">HTTP(S)</option>
|
||||||
|
<option value="socks4">Socks4</option>
|
||||||
|
<option value="socks5">Socks5 (This option supports Tor)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Hostname</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" placeholder="localhost" name="proxyHostname" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Port</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="number" placeholder="8080" name="proxyPort" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Username</label>
|
||||||
|
|
||||||
|
<div class="col-sm-1 col-sm-push-4 help-inline">
|
||||||
|
<i class="icon-sonarr-form-info" title="You only need to enter a username and password if one is required. Leave them blank otherwise."/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4 col-sm-pull-1">
|
||||||
|
<input type="text" name="proxyUsername" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Password</label>
|
||||||
|
|
||||||
|
<div class="col-sm-1 col-sm-push-4 help-inline">
|
||||||
|
<i class="icon-sonarr-form-info" title="You only need to enter a username and password if one is required. Leave them blank otherwise."/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4 col-sm-pull-1">
|
||||||
|
<input type="password" name="proxyPassword" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Addresses for the proxy to ignore</label>
|
||||||
|
|
||||||
|
<div class="col-sm-1 col-sm-push-4 help-inline">
|
||||||
|
<i class="icon-sonarr-form-info" title="Use ';' as a separator"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4 col-sm-pull-1">
|
||||||
|
<input type="text" name="proxySubnetFilter" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Bypass Proxy for Local Addresses?</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<label class="checkbox toggle well">
|
||||||
|
<input type="checkbox" name="proxyBypassLocalAddresses" class="form-control"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span>Yes</span>
|
||||||
|
<span>No</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="btn btn-primary slide-button"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Logging</legend>
|
<legend>Logging</legend>
|
||||||
|
Loading…
Reference in New Issue
Block a user