mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
SSL Fix by default, Added support of TLS 1.1 & 1.2 (#337)
* SSL Fix by default, Now use TLS (1.2, 1.1, 1) by default * Workaround to use TLS 1.2 & 1.1 on Mono < 4.3
This commit is contained in:
@@ -1,13 +1,28 @@
|
|||||||
using System;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CurlSharp
|
namespace CurlSharp
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Our SSL FIX for CURL contain authorized Ciphers for SSL Communications
|
||||||
|
/// </summary>
|
||||||
public class SSLFix
|
public class SSLFix
|
||||||
{
|
{
|
||||||
public const string CipherList = "rsa_aes_128_sha,ecdhe_rsa_aes_256_sha,ecdhe_ecdsa_aes_128_sha";
|
// Our CiphersList
|
||||||
|
private static readonly ReadOnlyCollection<string> Ciphers = new ReadOnlyCollection<string>( new[] {
|
||||||
|
// Default supported ciphers by Jackett
|
||||||
|
"rsa_aes_128_sha",
|
||||||
|
"ecdhe_rsa_aes_256_sha",
|
||||||
|
"ecdhe_ecdsa_aes_128_sha"
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of ciphers supported by Jackett
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Formatted string of ciphers</returns>
|
||||||
|
public static string CiphersList()
|
||||||
|
{
|
||||||
|
// Comma-Separated list of ciphers
|
||||||
|
return string.Join(",", Ciphers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -127,11 +127,11 @@ namespace Jackett
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Startup.DoSSLFix == true)
|
if (Startup.DoSSLFix.GetValueOrDefault(true))
|
||||||
{
|
{
|
||||||
// http://stackoverflow.com/questions/31107851/how-to-fix-curl-35-cannot-communicate-securely-with-peer-no-common-encryptio
|
// http://stackoverflow.com/questions/31107851/how-to-fix-curl-35-cannot-communicate-securely-with-peer-no-common-encryptio
|
||||||
// https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html
|
// https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html
|
||||||
easy.SslCipherList = SSLFix.CipherList;
|
easy.SslCipherList = SSLFix.CiphersList();
|
||||||
easy.FreshConnect = true;
|
easy.FreshConnect = true;
|
||||||
easy.ForbidReuse = true;
|
easy.ForbidReuse = true;
|
||||||
}
|
}
|
||||||
|
@@ -69,6 +69,13 @@ namespace Jackett.Utils.Clients
|
|||||||
proxyServer = new WebProxy(Startup.ProxyConnection, false);
|
proxyServer = new WebProxy(Startup.ProxyConnection, false);
|
||||||
useProxy = true;
|
useProxy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityProtocolType values below not available in Mono < 4.3
|
||||||
|
const int SecurityProtocolTypeTls11 = 768;
|
||||||
|
const int SecurityProtocolTypeTls12 = 3072;
|
||||||
|
// Specify to use TLS 1.2 as default connection
|
||||||
|
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)(SecurityProtocolTypeTls12 | SecurityProtocolTypeTls11);
|
||||||
|
|
||||||
var client = new HttpClient(new HttpClientHandler
|
var client = new HttpClient(new HttpClientHandler
|
||||||
{
|
{
|
||||||
CookieContainer = cookies,
|
CookieContainer = cookies,
|
||||||
|
@@ -1,116 +1,116 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using CurlSharp;
|
using CurlSharp;
|
||||||
using Jackett.Models;
|
using Jackett.Models;
|
||||||
using Jackett.Services;
|
using Jackett.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Jackett.Utils.Clients
|
namespace Jackett.Utils.Clients
|
||||||
{
|
{
|
||||||
public class UnixSafeCurlWebClient : IWebClient
|
public class UnixSafeCurlWebClient : IWebClient
|
||||||
{
|
{
|
||||||
IProcessService processService;
|
IProcessService processService;
|
||||||
Logger logger;
|
Logger logger;
|
||||||
IConfigurationService configService;
|
IConfigurationService configService;
|
||||||
|
|
||||||
public UnixSafeCurlWebClient(IProcessService p, Logger l, IConfigurationService c)
|
public UnixSafeCurlWebClient(IProcessService p, Logger l, IConfigurationService c)
|
||||||
{
|
{
|
||||||
processService = p;
|
processService = p;
|
||||||
logger = l;
|
logger = l;
|
||||||
configService = c;
|
configService = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WebClientByteResult> GetBytes(WebRequest request)
|
public async Task<WebClientByteResult> GetBytes(WebRequest request)
|
||||||
{
|
{
|
||||||
logger.Debug(string.Format("UnixSafeCurlWebClient:GetBytes(Url:{0})", request.Url));
|
logger.Debug(string.Format("UnixSafeCurlWebClient:GetBytes(Url:{0})", request.Url));
|
||||||
var result = await Run(request);
|
var result = await Run(request);
|
||||||
logger.Debug(string.Format("UnixSafeCurlWebClient: Returning {0} => {1} bytes", result.Status, (result.Content == null ? "<NULL>" : result.Content.Length.ToString())));
|
logger.Debug(string.Format("UnixSafeCurlWebClient: Returning {0} => {1} bytes", result.Status, (result.Content == null ? "<NULL>" : result.Content.Length.ToString())));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WebClientStringResult> GetString(WebRequest request)
|
public async Task<WebClientStringResult> GetString(WebRequest request)
|
||||||
{
|
{
|
||||||
logger.Debug(string.Format("UnixSafeCurlWebClient:GetString(Url:{0})", request.Url));
|
logger.Debug(string.Format("UnixSafeCurlWebClient:GetString(Url:{0})", request.Url));
|
||||||
var result = await Run(request);
|
var result = await Run(request);
|
||||||
logger.Debug(string.Format("UnixSafeCurlWebClient: Returning {0} => {1}", result.Status, (result.Content == null ? "<NULL>" : Encoding.UTF8.GetString(result.Content))));
|
logger.Debug(string.Format("UnixSafeCurlWebClient: Returning {0} => {1}", result.Status, (result.Content == null ? "<NULL>" : Encoding.UTF8.GetString(result.Content))));
|
||||||
return Mapper.Map<WebClientStringResult>(result);
|
return Mapper.Map<WebClientStringResult>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<WebClientByteResult> Run(WebRequest request)
|
private async Task<WebClientByteResult> Run(WebRequest request)
|
||||||
{
|
{
|
||||||
var args = new StringBuilder();
|
var args = new StringBuilder();
|
||||||
if (Startup.ProxyConnection != null)
|
if (Startup.ProxyConnection != null)
|
||||||
{
|
{
|
||||||
args.AppendFormat("-x " + Startup.ProxyConnection + " ");
|
args.AppendFormat("-x " + Startup.ProxyConnection + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
args.AppendFormat("--url \"{0}\" ", request.Url);
|
args.AppendFormat("--url \"{0}\" ", request.Url);
|
||||||
|
|
||||||
if (request.EmulateBrowser)
|
if (request.EmulateBrowser)
|
||||||
args.AppendFormat("-i -sS --user-agent \"{0}\" ", BrowserUtil.ChromeUserAgent);
|
args.AppendFormat("-i -sS --user-agent \"{0}\" ", BrowserUtil.ChromeUserAgent);
|
||||||
else
|
else
|
||||||
args.AppendFormat("-i -sS --user-agent \"{0}\" ", "Jackett/" + configService.GetVersion());
|
args.AppendFormat("-i -sS --user-agent \"{0}\" ", "Jackett/" + configService.GetVersion());
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(request.Cookies))
|
if (!string.IsNullOrWhiteSpace(request.Cookies))
|
||||||
{
|
{
|
||||||
args.AppendFormat("--cookie \"{0}\" ", request.Cookies);
|
args.AppendFormat("--cookie \"{0}\" ", request.Cookies);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(request.Referer))
|
if (!string.IsNullOrWhiteSpace(request.Referer))
|
||||||
{
|
{
|
||||||
args.AppendFormat("--referer \"{0}\" ", request.Referer);
|
args.AppendFormat("--referer \"{0}\" ", request.Referer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(request.RawBody))
|
if (!string.IsNullOrEmpty(request.RawBody))
|
||||||
{
|
{
|
||||||
var postString = StringUtil.PostDataFromDict(request.PostData);
|
var postString = StringUtil.PostDataFromDict(request.PostData);
|
||||||
args.AppendFormat("--data \"{0}\" ", request.RawBody.Replace("\"", "\\\""));
|
args.AppendFormat("--data \"{0}\" ", request.RawBody.Replace("\"", "\\\""));
|
||||||
} else if (request.PostData != null && request.PostData.Count() > 0)
|
} else if (request.PostData != null && request.PostData.Count() > 0)
|
||||||
{
|
{
|
||||||
var postString = StringUtil.PostDataFromDict(request.PostData);
|
var postString = StringUtil.PostDataFromDict(request.PostData);
|
||||||
args.AppendFormat("--data \"{0}\" ", postString);
|
args.AppendFormat("--data \"{0}\" ", postString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tempFile = Path.GetTempFileName();
|
var tempFile = Path.GetTempFileName();
|
||||||
args.AppendFormat("--output \"{0}\" ", tempFile);
|
args.AppendFormat("--output \"{0}\" ", tempFile);
|
||||||
|
|
||||||
if (Startup.DoSSLFix == true)
|
if (Startup.DoSSLFix.GetValueOrDefault(true))
|
||||||
{
|
{
|
||||||
// http://stackoverflow.com/questions/31107851/how-to-fix-curl-35-cannot-communicate-securely-with-peer-no-common-encryptio
|
// http://stackoverflow.com/questions/31107851/how-to-fix-curl-35-cannot-communicate-securely-with-peer-no-common-encryptio
|
||||||
// https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html
|
// https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html
|
||||||
args.Append("--cipher " + SSLFix.CipherList);
|
args.Append("--cipher " + SSLFix.CiphersList());
|
||||||
}
|
}
|
||||||
if (Startup.IgnoreSslErrors == true)
|
if (Startup.IgnoreSslErrors == true)
|
||||||
{
|
{
|
||||||
args.Append("-k ");
|
args.Append("-k ");
|
||||||
}
|
}
|
||||||
args.Append("-H \"Accept-Language: en-US,en\" ");
|
args.Append("-H \"Accept-Language: en-US,en\" ");
|
||||||
args.Append("-H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\" ");
|
args.Append("-H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\" ");
|
||||||
string stdout = null;
|
string stdout = null;
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix ? "curl" : "curl.exe", args.ToString() , true);
|
stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix ? "curl" : "curl.exe", args.ToString() , true);
|
||||||
});
|
});
|
||||||
|
|
||||||
var outputData = File.ReadAllBytes(tempFile);
|
var outputData = File.ReadAllBytes(tempFile);
|
||||||
File.Delete(tempFile);
|
File.Delete(tempFile);
|
||||||
stdout = Encoding.UTF8.GetString(outputData);
|
stdout = Encoding.UTF8.GetString(outputData);
|
||||||
var result = new WebClientByteResult();
|
var result = new WebClientByteResult();
|
||||||
var headSplit = stdout.IndexOf("\r\n\r\n");
|
var headSplit = stdout.IndexOf("\r\n\r\n");
|
||||||
if (headSplit < 0)
|
if (headSplit < 0)
|
||||||
throw new Exception("Invalid response");
|
throw new Exception("Invalid response");
|
||||||
var headers = stdout.Substring(0, headSplit);
|
var headers = stdout.Substring(0, headSplit);
|
||||||
if (Startup.ProxyConnection != null)
|
if (Startup.ProxyConnection != null)
|
||||||
{
|
{
|
||||||
// the proxy provided headers too so we need to split headers again
|
// the proxy provided headers too so we need to split headers again
|
||||||
@@ -121,39 +121,39 @@ namespace Jackett.Utils.Clients
|
|||||||
headSplit = headSplit1;
|
headSplit = headSplit1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var headerCount = 0;
|
var headerCount = 0;
|
||||||
var cookieBuilder = new StringBuilder();
|
var cookieBuilder = new StringBuilder();
|
||||||
var cookies = new List<Tuple<string, string>>();
|
var cookies = new List<Tuple<string, string>>();
|
||||||
|
|
||||||
foreach (var header in headers.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (var header in headers.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (headerCount == 0)
|
if (headerCount == 0)
|
||||||
{
|
{
|
||||||
var responseCode = int.Parse(header.Split(' ')[1]);
|
var responseCode = int.Parse(header.Split(' ')[1]);
|
||||||
result.Status = (HttpStatusCode)responseCode;
|
result.Status = (HttpStatusCode)responseCode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var headerSplitIndex = header.IndexOf(':');
|
var headerSplitIndex = header.IndexOf(':');
|
||||||
if (headerSplitIndex > 0)
|
if (headerSplitIndex > 0)
|
||||||
{
|
{
|
||||||
var name = header.Substring(0, headerSplitIndex).ToLowerInvariant();
|
var name = header.Substring(0, headerSplitIndex).ToLowerInvariant();
|
||||||
var value = header.Substring(headerSplitIndex + 1);
|
var value = header.Substring(headerSplitIndex + 1);
|
||||||
switch (name)
|
switch (name)
|
||||||
{
|
{
|
||||||
case "set-cookie":
|
case "set-cookie":
|
||||||
var nameSplit = value.IndexOf('=');
|
var nameSplit = value.IndexOf('=');
|
||||||
if (nameSplit > -1)
|
if (nameSplit > -1)
|
||||||
{
|
{
|
||||||
cookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') + 1)));
|
cookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') + 1)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "location":
|
case "location":
|
||||||
result.RedirectingTo = value.Trim();
|
result.RedirectingTo = value.Trim();
|
||||||
break;
|
break;
|
||||||
case "refresh":
|
case "refresh":
|
||||||
//"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R"
|
//"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R"
|
||||||
var redirval = "";
|
var redirval = "";
|
||||||
var start = value.IndexOf("=");
|
var start = value.IndexOf("=");
|
||||||
var end = value.IndexOf(";");
|
var end = value.IndexOf(";");
|
||||||
var len = value.Length;
|
var len = value.Length;
|
||||||
@@ -167,31 +167,31 @@ namespace Jackett.Utils.Clients
|
|||||||
result.Status = System.Net.HttpStatusCode.Redirect;
|
result.Status = System.Net.HttpStatusCode.Redirect;
|
||||||
var redirtime = Int32.Parse(value.Substring(0, end));
|
var redirtime = Int32.Parse(value.Substring(0, end));
|
||||||
System.Threading.Thread.Sleep(redirtime * 1000);
|
System.Threading.Thread.Sleep(redirtime * 1000);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headerCount++;
|
headerCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var cookieGroup in cookies.GroupBy(c => c.Item1))
|
foreach (var cookieGroup in cookies.GroupBy(c => c.Item1))
|
||||||
{
|
{
|
||||||
cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2);
|
cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Cookies = cookieBuilder.ToString().Trim();
|
result.Cookies = cookieBuilder.ToString().Trim();
|
||||||
result.Content = new byte[outputData.Length - (headSplit + 3)];
|
result.Content = new byte[outputData.Length - (headSplit + 3)];
|
||||||
var dest = 0;
|
var dest = 0;
|
||||||
for (int i = headSplit + 4; i < outputData.Length; i++)
|
for (int i = headSplit + 4; i < outputData.Length; i++)
|
||||||
{
|
{
|
||||||
result.Content[dest] = outputData[i];
|
result.Content[dest] = outputData[i];
|
||||||
dest++;
|
dest++;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("WebClientByteResult returned " + result.Status);
|
logger.Debug("WebClientByteResult returned " + result.Status);
|
||||||
ServerUtil.ResureRedirectIsFullyQualified(request, result);
|
ServerUtil.ResureRedirectIsFullyQualified(request, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user