diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs index 567a7bb22..184adce0f 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs @@ -1,12 +1,17 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudflareSolverRe; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; using Jackett.Common.Helpers; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; @@ -16,19 +21,106 @@ namespace Jackett.Common.Utils.Clients { public class HttpWebClient : WebClient { + protected static Dictionary> trustedCertificates = new Dictionary>(); + protected static string webProxyUrl; + protected static IWebProxy webProxy; + + [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages + public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + var hash = certificate.GetCertHashString(); + + + trustedCertificates.TryGetValue(hash, out var hosts); + if (hosts != null) + { + if (hosts.Contains(request.RequestUri.Host)) + return true; + } + + if (sslPolicyErrors != SslPolicyErrors.None) + { + // Throw exception with certificate details, this will cause a "Exception User-Unhandled" when running it in the Visual Studio debugger. + // The certificate is only available inside this function, so we can't catch it at the calling method. + throw new Exception("certificate validation failed: " + certificate.ToString()); + } + + return sslPolicyErrors == SslPolicyErrors.None; + } + + public static void InitProxy(ServerConfig serverConfig) + { + // dispose old SocksWebProxy + if (webProxy is SocksWebProxy proxy) + proxy.Dispose(); + webProxy = null; + webProxyUrl = serverConfig.GetProxyUrl(); + if (!string.IsNullOrWhiteSpace(webProxyUrl)) + { + if (serverConfig.ProxyType != ProxyType.Http) + { + var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; + var socksConfig = new ProxyConfig + { + SocksAddress = addresses.FirstOrDefault(), + Username = serverConfig.ProxyUsername, + Password = serverConfig.ProxyPassword, + Version = serverConfig.ProxyType == ProxyType.Socks4 ? + ProxyConfig.SocksVersion.Four : + ProxyConfig.SocksVersion.Five + }; + if (serverConfig.ProxyPort.HasValue) + { + socksConfig.SocksPort = serverConfig.ProxyPort.Value; + } + webProxy = new SocksWebProxy(socksConfig, false); + } + else + { + NetworkCredential creds = null; + if (!serverConfig.ProxyIsAnonymous) + { + var username = serverConfig.ProxyUsername; + var password = serverConfig.ProxyPassword; + creds = new NetworkCredential(username, password); + } + webProxy = new WebProxy(webProxyUrl) + { + BypassProxyOnLocal = false, + Credentials = creds + }; + } + } + } + public HttpWebClient(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc) : base(p: p, l: l, c: c, sc: sc) { + if (webProxyUrl == null) + InitProxy(sc); + } + + // Called everytime the ServerConfig changes + public override void OnNext(ServerConfig value) + { + var newProxyUrl = serverConfig.GetProxyUrl(); + if (webProxyUrl != newProxyUrl) // if proxy URL changed + InitProxy(serverConfig); } public override void Init() { ServicePointManager.DefaultConnectionLimit = 1000; - base.Init(); + if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } + } protected override async Task Run(WebRequest webRequest) @@ -209,5 +301,17 @@ namespace Jackett.Common.Utils.Clients } } } + + public override void AddTrustedCertificate(string host, string hash) + { + hash = hash.ToUpper(); + trustedCertificates.TryGetValue(hash.ToUpper(), out var hosts); + if (hosts == null) + { + hosts = new HashSet(); + trustedCertificates[hash] = hosts; + } + hosts.Add(host); + } } } diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs index 117020ac3..f8ea2f9d8 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs @@ -1,12 +1,17 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudflareSolverRe; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; using Jackett.Common.Helpers; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; @@ -22,13 +27,88 @@ namespace Jackett.Common.Utils.Clients private ClearanceHandler clearanceHandlr; private HttpClientHandler clientHandlr; private HttpClient client; - + + protected static Dictionary> trustedCertificates = new Dictionary>(); + protected static string webProxyUrl; + protected static IWebProxy webProxy; + + [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages + public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + var hash = certificate.GetCertHashString(); + + + trustedCertificates.TryGetValue(hash, out var hosts); + if (hosts != null) + { + if (hosts.Contains(request.RequestUri.Host)) + return true; + } + + if (sslPolicyErrors != SslPolicyErrors.None) + { + // Throw exception with certificate details, this will cause a "Exception User-Unhandled" when running it in the Visual Studio debugger. + // The certificate is only available inside this function, so we can't catch it at the calling method. + throw new Exception("certificate validation failed: " + certificate.ToString()); + } + + return sslPolicyErrors == SslPolicyErrors.None; + } + + public static void InitProxy(ServerConfig serverConfig) + { + // dispose old SocksWebProxy + if (webProxy is SocksWebProxy proxy) + proxy.Dispose(); + webProxy = null; + webProxyUrl = serverConfig.GetProxyUrl(); + if (!string.IsNullOrWhiteSpace(webProxyUrl)) + { + if (serverConfig.ProxyType != ProxyType.Http) + { + var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; + var socksConfig = new ProxyConfig + { + SocksAddress = addresses.FirstOrDefault(), + Username = serverConfig.ProxyUsername, + Password = serverConfig.ProxyPassword, + Version = serverConfig.ProxyType == ProxyType.Socks4 ? + ProxyConfig.SocksVersion.Four : + ProxyConfig.SocksVersion.Five + }; + if (serverConfig.ProxyPort.HasValue) + { + socksConfig.SocksPort = serverConfig.ProxyPort.Value; + } + webProxy = new SocksWebProxy(socksConfig, false); + } + else + { + NetworkCredential creds = null; + if (!serverConfig.ProxyIsAnonymous) + { + var username = serverConfig.ProxyUsername; + var password = serverConfig.ProxyPassword; + creds = new NetworkCredential(username, password); + } + webProxy = new WebProxy(webProxyUrl) + { + BypassProxyOnLocal = false, + Credentials = creds + }; + } + } + } + public HttpWebClient2(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc) : base(p: p, l: l, c: c, sc: sc) { + if (webProxyUrl == null) + InitProxy(sc); + cookies = new CookieContainer(); CreateClient(); } @@ -59,7 +139,10 @@ namespace Jackett.Common.Utils.Clients // Called everytime the ServerConfig changes public override void OnNext(ServerConfig value) { - base.OnNext(value); + var newProxyUrl = serverConfig.GetProxyUrl(); + if (webProxyUrl != newProxyUrl) // if proxy URL changed + InitProxy(serverConfig); + // recreate client if needed (can't just change the proxy attribute) if (!ReferenceEquals(clientHandlr.Proxy, webProxy)) { @@ -69,7 +152,11 @@ namespace Jackett.Common.Utils.Clients public override void Init() { - base.Init(); + if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient2: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; } @@ -229,5 +316,17 @@ namespace Jackett.Common.Utils.Clients ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); return result; } + + public override void AddTrustedCertificate(string host, string hash) + { + hash = hash.ToUpper(); + trustedCertificates.TryGetValue(hash.ToUpper(), out var hosts); + if (hosts == null) + { + hosts = new HashSet(); + trustedCertificates[hash] = hosts; + } + hosts.Add(host); + } } } diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient2NetCore.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient2NetCore.cs index b0260d3fc..34f111bb5 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient2NetCore.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient2NetCore.cs @@ -1,12 +1,17 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudflareSolverRe; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; using Jackett.Common.Helpers; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; @@ -23,12 +28,87 @@ namespace Jackett.Common.Utils.Clients private HttpClientHandler clientHandlr; private HttpClient client; + protected static Dictionary> trustedCertificates = new Dictionary>(); + protected static string webProxyUrl; + protected static IWebProxy webProxy; + + [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages + public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + var hash = certificate.GetCertHashString(); + + + trustedCertificates.TryGetValue(hash, out var hosts); + if (hosts != null) + { + if (hosts.Contains(request.RequestUri.Host)) + return true; + } + + if (sslPolicyErrors != SslPolicyErrors.None) + { + // Throw exception with certificate details, this will cause a "Exception User-Unhandled" when running it in the Visual Studio debugger. + // The certificate is only available inside this function, so we can't catch it at the calling method. + throw new Exception("certificate validation failed: " + certificate.ToString()); + } + + return sslPolicyErrors == SslPolicyErrors.None; + } + + public static void InitProxy(ServerConfig serverConfig) + { + // dispose old SocksWebProxy + if (webProxy is SocksWebProxy proxy) + proxy.Dispose(); + webProxy = null; + webProxyUrl = serverConfig.GetProxyUrl(); + if (!string.IsNullOrWhiteSpace(webProxyUrl)) + { + if (serverConfig.ProxyType != ProxyType.Http) + { + var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; + var socksConfig = new ProxyConfig + { + SocksAddress = addresses.FirstOrDefault(), + Username = serverConfig.ProxyUsername, + Password = serverConfig.ProxyPassword, + Version = serverConfig.ProxyType == ProxyType.Socks4 ? + ProxyConfig.SocksVersion.Four : + ProxyConfig.SocksVersion.Five + }; + if (serverConfig.ProxyPort.HasValue) + { + socksConfig.SocksPort = serverConfig.ProxyPort.Value; + } + webProxy = new SocksWebProxy(socksConfig, false); + } + else + { + NetworkCredential creds = null; + if (!serverConfig.ProxyIsAnonymous) + { + var username = serverConfig.ProxyUsername; + var password = serverConfig.ProxyPassword; + creds = new NetworkCredential(username, password); + } + webProxy = new WebProxy(webProxyUrl) + { + BypassProxyOnLocal = false, + Credentials = creds + }; + } + } + } + public HttpWebClient2NetCore(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc) : base(p: p, l: l, c: c, sc: sc) { + if (webProxyUrl == null) + InitProxy(sc); + cookies = new CookieContainer(); CreateClient(); } @@ -59,7 +139,10 @@ namespace Jackett.Common.Utils.Clients // Called everytime the ServerConfig changes public override void OnNext(ServerConfig value) { - base.OnNext(value); + var newProxyUrl = serverConfig.GetProxyUrl(); + if (webProxyUrl != newProxyUrl) // if proxy URL changed + InitProxy(serverConfig); + // recreate client if needed (can't just change the proxy attribute) if (!ReferenceEquals(clientHandlr.Proxy, webProxy)) { @@ -71,7 +154,11 @@ namespace Jackett.Common.Utils.Clients { ServicePointManager.DefaultConnectionLimit = 1000; - base.Init(); + if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } } protected override async Task Run(WebRequest webRequest) @@ -229,5 +316,17 @@ namespace Jackett.Common.Utils.Clients ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); return result; } + + public override void AddTrustedCertificate(string host, string hash) + { + hash = hash.ToUpper(); + trustedCertificates.TryGetValue(hash.ToUpper(), out var hosts); + if (hosts == null) + { + hosts = new HashSet(); + trustedCertificates[hash] = hosts; + } + hosts.Add(host); + } } } diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClientNetCore.cs b/src/Jackett.Common/Utils/Clients/HttpWebClientNetCore.cs index 71cfa3b6e..afa458ee5 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClientNetCore.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClientNetCore.cs @@ -1,12 +1,17 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudflareSolverRe; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; using Jackett.Common.Helpers; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; @@ -17,18 +22,107 @@ namespace Jackett.Common.Utils.Clients // custom HttpWebClient based WebClient for netcore (due to changed custom certificate validation API) public class HttpWebClientNetCore : WebClient { + protected static Dictionary> trustedCertificates = new Dictionary>(); + protected static string webProxyUrl; + protected static IWebProxy webProxy; + + [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages + public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + { + var hash = certificate.GetCertHashString(); + + + trustedCertificates.TryGetValue(hash, out var hosts); + if (hosts != null) + { + if (hosts.Contains(request.RequestUri.Host)) + return true; + } + + if (sslPolicyErrors != SslPolicyErrors.None) + { + // Throw exception with certificate details, this will cause a "Exception User-Unhandled" when running it in the Visual Studio debugger. + // The certificate is only available inside this function, so we can't catch it at the calling method. + throw new Exception("certificate validation failed: " + certificate.ToString()); + } + + return sslPolicyErrors == SslPolicyErrors.None; + } + } + + public static void InitProxy(ServerConfig serverConfig) + { + // dispose old SocksWebProxy + if (webProxy is SocksWebProxy proxy) + proxy.Dispose(); + webProxy = null; + webProxyUrl = serverConfig.GetProxyUrl(); + if (!string.IsNullOrWhiteSpace(webProxyUrl)) + { + if (serverConfig.ProxyType != ProxyType.Http) + { + var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; + var socksConfig = new ProxyConfig + { + SocksAddress = addresses.FirstOrDefault(), + Username = serverConfig.ProxyUsername, + Password = serverConfig.ProxyPassword, + Version = serverConfig.ProxyType == ProxyType.Socks4 ? + ProxyConfig.SocksVersion.Four : + ProxyConfig.SocksVersion.Five + }; + if (serverConfig.ProxyPort.HasValue) + { + socksConfig.SocksPort = serverConfig.ProxyPort.Value; + } + webProxy = new SocksWebProxy(socksConfig, false); + } + else + { + NetworkCredential creds = null; + if (!serverConfig.ProxyIsAnonymous) + { + var username = serverConfig.ProxyUsername; + var password = serverConfig.ProxyPassword; + creds = new NetworkCredential(username, password); + } + webProxy = new WebProxy(webProxyUrl) + { + BypassProxyOnLocal = false, + Credentials = creds + }; + } + } + } + public HttpWebClientNetCore(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc) : base(p: p, l: l, c: c, sc: sc) { + if (webProxyUrl == null) + InitProxy(sc); } + + // Called everytime the ServerConfig changes + public override void OnNext(ServerConfig value) + { + var newProxyUrl = serverConfig.GetProxyUrl(); + if (webProxyUrl != newProxyUrl) // if proxy URL changed + InitProxy(serverConfig); + } + public override void Init() { ServicePointManager.DefaultConnectionLimit = 1000; - base.Init(); + if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } } protected override async Task Run(WebRequest webRequest) @@ -210,5 +304,17 @@ namespace Jackett.Common.Utils.Clients } } } + + public override void AddTrustedCertificate(string host, string hash) + { + hash = hash.ToUpper(); + trustedCertificates.TryGetValue(hash.ToUpper(), out var hosts); + if (hosts == null) + { + hosts = new HashSet(); + trustedCertificates[hash] = hosts; + } + hosts.Add(host); + } } } diff --git a/src/Jackett.Common/Utils/Clients/WebClient.cs b/src/Jackett.Common/Utils/Clients/WebClient.cs index 03f1d127f..602269d25 100644 --- a/src/Jackett.Common/Utils/Clients/WebClient.cs +++ b/src/Jackett.Common/Utils/Clients/WebClient.cs @@ -1,18 +1,12 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using AutoMapper; -using com.LandonKey.SocksWebProxy; -using com.LandonKey.SocksWebProxy.Proxy; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; using NLog; @@ -30,82 +24,6 @@ namespace Jackett.Common.Utils.Clients protected TimeSpan requestDelayTimeSpan; protected string ClientType; public bool EmulateBrowser = true; - - protected static Dictionary> trustedCertificates = new Dictionary>(); - protected static string webProxyUrl; - protected static IWebProxy webProxy; - - - [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages - public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - { - var hash = certificate.GetCertHashString(); - - - trustedCertificates.TryGetValue(hash, out var hosts); - if (hosts != null) - { - if (hosts.Contains(request.RequestUri.Host)) - return true; - } - - if (sslPolicyErrors != SslPolicyErrors.None) - { - // Throw exception with certificate details, this will cause a "Exception User-Unhandled" when running it in the Visual Studio debugger. - // The certificate is only available inside this function, so we can't catch it at the calling method. - throw new Exception("certificate validation failed: " + certificate.ToString()); - } - - return sslPolicyErrors == SslPolicyErrors.None; - } - } - public static void InitProxy(ServerConfig serverConfig) - { - // dispose old SocksWebProxy - if (webProxy is SocksWebProxy proxy) - proxy.Dispose(); - webProxy = null; - webProxyUrl = serverConfig.GetProxyUrl(); - if (!string.IsNullOrWhiteSpace(webProxyUrl)) - { - if (serverConfig.ProxyType != ProxyType.Http) - { - var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; - var socksConfig = new ProxyConfig - { - SocksAddress = addresses.FirstOrDefault(), - Username = serverConfig.ProxyUsername, - Password = serverConfig.ProxyPassword, - Version = serverConfig.ProxyType == ProxyType.Socks4 ? - ProxyConfig.SocksVersion.Four : - ProxyConfig.SocksVersion.Five - }; - if (serverConfig.ProxyPort.HasValue) - { - socksConfig.SocksPort = serverConfig.ProxyPort.Value; - } - webProxy = new SocksWebProxy(socksConfig, false); - } - else - { - NetworkCredential creds = null; - if (!serverConfig.ProxyIsAnonymous) - { - var username = serverConfig.ProxyUsername; - var password = serverConfig.ProxyPassword; - creds = new NetworkCredential(username, password); - } - webProxy = new WebProxy(webProxyUrl) - { - BypassProxyOnLocal = false, - Credentials = creds - }; - } - } - } - - public double requestDelay { get => requestDelayTimeSpan.TotalSeconds; @@ -118,14 +36,7 @@ namespace Jackett.Common.Utils.Clients public virtual void AddTrustedCertificate(string host, string hash) { - hash = hash.ToUpper(); - trustedCertificates.TryGetValue(hash.ToUpper(), out var hosts); - if (hosts == null) - { - hosts = new HashSet(); - trustedCertificates[hash] = hosts; - } - hosts.Add(host); + // not implemented by default } public WebClient(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc) @@ -136,9 +47,6 @@ namespace Jackett.Common.Utils.Clients serverConfig = sc; ClientType = GetType().Name; ServerConfigUnsubscriber = serverConfig.Subscribe(this); - - if (webProxyUrl == null) - InitProxy(sc); } protected async Task DelayRequest(WebRequest request) @@ -222,15 +130,7 @@ namespace Jackett.Common.Utils.Clients protected virtual async Task Run(WebRequest webRequest) => throw new NotImplementedException(); #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - public virtual void Init() - { - if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) - { - logger.Info($"WebClient({ClientType}): Disabling certificate validation"); - ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; - } - } - + public abstract void Init(); public virtual void OnCompleted() => throw new NotImplementedException(); @@ -238,9 +138,7 @@ namespace Jackett.Common.Utils.Clients public virtual void OnNext(ServerConfig value) { - var newProxyUrl = serverConfig.GetProxyUrl(); - if (webProxyUrl != newProxyUrl) // if proxy URL changed - InitProxy(serverConfig); + // nothing by default } /**