Files
SteamTools/src/ST.Client/Services/Implementation/HttpProxyServiceImpl.cs
T
2021-12-05 14:26:20 +08:00

764 lines
33 KiB
C#

using System.Application.Models;
using System.Application.Properties;
using System.Application.UI.Resx;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Properties;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace System.Application.Services.Implementation
{
public class HttpProxyServiceImpl : IHttpProxyService
{
protected readonly IPlatformService platformService;
readonly ProxyServer proxyServer = new();
public bool IsCertificate => proxyServer.CertificateManager == null || proxyServer.CertificateManager.RootCertificate == null;
public IReadOnlyCollection<AccelerateProjectDTO>? ProxyDomains { get; set; }
public IReadOnlyCollection<ScriptDTO>? Scripts { get; set; }
public bool IsEnableScript { get; set; }
public bool IsOnlyWorkSteamBrowser { get; set; }
public string CertificateName { get; set; } = ThisAssembly.AssemblyProduct;
public CertificateEngine CertificateEngine { get; set; } = CertificateEngine.BouncyCastle;
public int ProxyPort { get; set; } = 26501;
public IPAddress ProxyIp { get; set; } = IPAddress.Any;
public bool IsSystemProxy { get; set; }
public bool IsProxyGOG { get; set; }
public bool OnlyEnableProxyScript { get; set; }
public bool Socks5ProxyEnable { get; set; }
public int Socks5ProxyPortId { get; set; }
public bool TwoLevelAgentEnable { get; set; }
public ExternalProxyType TwoLevelAgentProxyType { get; set; }
= IHttpProxyService.DefaultTwoLevelAgentProxyType;
public string? TwoLevelAgentIp { get; set; }
public int TwoLevelAgentPortId { get; set; }
public string? TwoLevelAgentUserName { get; set; }
public string? TwoLevelAgentPassword { get; set; }
public string? ProxyDNS { get; set; }
public bool ProxyRunning => proxyServer.ProxyRunning;
public IList<HttpHeader> JsHeader => new List<HttpHeader>() { new HttpHeader("Content-Type", "text/javascript;charset=UTF-8") };
public HttpProxyServiceImpl(IPlatformService platformService)
{
this.platformService = platformService;
//if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
// proxyServer.CertificateManager.CertificateEngine = CertificateEngine.DefaultWindows;
//else
proxyServer.ExceptionFunc = ((Exception exception) =>
{
Log.Error("Proxy", exception, "ProxyServer ExceptionFunc");
});
proxyServer.EnableHttp2 = true;
proxyServer.EnableConnectionPool = true;
proxyServer.CheckCertificateRevocation = X509RevocationMode.NoCheck;
// 可选地设置证书引擎
proxyServer.CertificateManager.CertificateEngine = CertificateEngine;
//proxyServer.CertificateManager.PfxPassword = $"{CertificateName}";
//proxyServer.ThreadPoolWorkerThread = Environment.ProcessorCount * 8;
proxyServer.CertificateManager.PfxFilePath = Path.Combine(IOPath.AppDataDirectory, $@"{CertificateName}.Certificate.pfx");
proxyServer.CertificateManager.RootCertificateIssuerName = $"{CertificateName} Certificate Authority";
proxyServer.CertificateManager.RootCertificateName = $"{CertificateName} Certificate";
//proxyServer.CertificateManager.CertificateValidDays = 300;
//proxyServer.CertificateManager.SaveFakeCertificates = true;
proxyServer.CertificateManager.RootCertificate = proxyServer.CertificateManager.LoadRootCertificate();
}
private static async Task HttpRequest(SessionEventArgs e)
{
//IHttpService.Instance.SendAsync<object>();
var url = Web.HttpUtility.UrlDecode(e.HttpClient.Request.RequestUri.Query.Replace("?request=", ""));
var cookie = e.HttpClient.Request.Headers.GetFirstHeader("cookie-steamTool")?.Value ??
e.HttpClient.Request.Headers.GetFirstHeader("Cookie")?.Value;
var headrs = new List<HttpHeader>() {
new HttpHeader("Access-Control-Allow-Origin", e.HttpClient.Request.Headers.GetFirstHeader("Origin")?.Value ?? "*"),
new HttpHeader("Access-Control-Allow-Headers", "*"), new HttpHeader("Access-Control-Allow-Methods", "*"),
new HttpHeader("Access-Control-Allow-Credentials", "true")
};
//if (cookie != null)
// headrs.Add(new HttpHeader("Cookie", cookie));
if (e.HttpClient.Request.ContentType != null)
headrs.Add(new HttpHeader("Content-Type", e.HttpClient.Request.ContentType));
switch (e.HttpClient.Request.Method.ToUpperInvariant())
{
case "GET":
var body = await IHttpService.Instance.GetAsync<string>(url, cookie: cookie);
e.Ok(body ?? "500", headrs);
return;
case "POST":
try
{
if (e.HttpClient.Request.ContentLength > 0)
{
var conext = await IHttpService.Instance.SendAsync<string>(url, () =>
{
using var sw = new MemoryStream().GetWriter(leaveOpen: true);
sw.Write(e.HttpClient.Request.BodyString);
var req = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new StreamContent(sw.BaseStream),
};
req.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(e.HttpClient.Request.ContentType);
req.Content.Headers.ContentLength = e.HttpClient.Request.BodyString.Length;
return req;
}, null, false, new CancellationToken());
e.Ok(conext ?? "500", headrs);
}
else
{
e.Ok("500", headrs);
}
}
catch (Exception error)
{
e.Ok(error.Message ?? "500", headrs);
}
return;
}
//e.Ok(respone, new List<HttpHeader>() { new HttpHeader("Access-Control-Allow-Origin", e.HttpClient.Request.Headers.GetFirstHeader("Origin")?.Value ?? "*") });
}
private async Task OnRequest(object sender, SessionEventArgs e)
{
#if DEBUG
Debug.WriteLine("OnRequest " + e.HttpClient.Request.RequestUri.AbsoluteUri);
Debug.WriteLine("OnRequest HTTP " + e.HttpClient.Request.HttpVersion);
Debug.WriteLine("ClientRemoteEndPoint " + e.ClientRemoteEndPoint.ToString());
#endif
if (e.HttpClient.Request.Host == null) return;
if (e.HttpClient.Request.Host.Contains(IHttpProxyService.LocalDomain, StringComparison.OrdinalIgnoreCase))
{
if (e.HttpClient.Request.Method.ToUpperInvariant() == "OPTIONS")
{
e.Ok("", new List<HttpHeader>() {
new HttpHeader("Access-Control-Allow-Origin", e.HttpClient.Request.Headers.GetFirstHeader("Origin")?.Value ?? "*"),
new HttpHeader("Access-Control-Allow-Headers", "*"),
new HttpHeader("Access-Control-Allow-Methods", "*"),
new HttpHeader("Access-Control-Allow-Credentials", "true") });
return;
}
var type = e.HttpClient.Request.Headers.GetFirstHeader("requestType")?.Value;
switch (type)
{
case "xhr":
await HttpRequest(e);
return;
default:
e.Ok(Scripts.FirstOrDefault(x => x.JsPathUrl == e.HttpClient.Request.RequestUri.LocalPath)?.Content ?? "404", JsHeader);
return;
}
}
if (ProxyDomains is null || TwoLevelAgentEnable || OnlyEnableProxyScript) return;
foreach (var item in ProxyDomains)
{
foreach (var host in item.DomainNamesArray)
{
if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(host))
{
if (e.HttpClient.Request.RequestUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase))
{
e.HttpClient.Request.RequestUri = new Uri(e.HttpClient.Request.RequestUri.AbsoluteUri.Remove(0, 4).Insert(0, "https"));
//e.Redirect(e.HttpClient.Request.RequestUri.AbsoluteUri.Remove(0, 4).Insert(0, "https"));
//return;
}
if (item.Redirect)
{
var url = item.ForwardDomainName.Replace("{path}", e.HttpClient.Request.RequestUri.AbsolutePath);
url = url.Replace("{args}", e.HttpClient.Request.RequestUri.Query);
//url = url.Replace("{url}", e.HttpClient.Request.RequestUri.AbsoluteUri);
if (Browser2.IsHttpUrl(url))
{
e.HttpClient.Request.RequestUri = new Uri(e.HttpClient.Request.RequestUri.AbsoluteUri.Replace(e.HttpClient.Request.RequestUri.Scheme + "://" + e.HttpClient.Request.RequestUri.Host, url));
//e.Redirect(e.HttpClient.Request.RequestUri.AbsoluteUri.Replace(e.HttpClient.Request.RequestUri.Scheme + "://" + e.HttpClient.Request.RequestUri.Host, url));
return;
}
e.HttpClient.Request.RequestUri = new Uri(e.HttpClient.Request.RequestUri.AbsoluteUri.Replace(e.HttpClient.Request.RequestUri.Host, url));
//e.Redirect(e.HttpClient.Request.RequestUri.AbsoluteUri.Replace(e.HttpClient.Request.RequestUri.Host, url));
return;
}
IPAddress? ip = null;
if (!item.ForwardDomainIsNameOrIP)
{
ip = IPAddress2.Parse(item.ForwardDomainIP);
}
else
{
if (IPAddress.TryParse(ProxyDNS, out var dns))
{
ip = (await DnsAnalysis.AnalysisDomainIpByCustomDns(item.ForwardDomainName, new[] { dns }))?.First();
}
else
{
if (!OperatingSystem2.IsWindows)
{
ip = (await DnsAnalysis.AnalysisDomainIp(item.ForwardDomainName))?.First();
}
else
{
//非windows环境不能使用系统默认DNS解析代理,会解析到hosts上无限循环
ip = (await DnsAnalysis.AnalysisDomainIpByAliDns(item.ForwardDomainName))?.First();
}
}
}
if (ip == null || IPAddress.IsLoopback(ip) || ip == IPAddress.Any)
goto exit;
e.HttpClient.UpStreamEndPoint = new IPEndPoint(ip, item.PortId);
//e.HttpClient.Request.Host = item.ForwardDomainName ?? e.HttpClient.Request.Host;
if (e.HttpClient.ConnectRequest?.ClientHelloInfo?.Extensions != null)
{
#if DEBUG
//Logger.Info("ClientHelloInfo Info: " + e.HttpClient.ConnectRequest.ClientHelloInfo);
Debug.WriteLine("ClientHelloInfo Info: " + e.HttpClient.ConnectRequest.ClientHelloInfo);
#endif
if (!string.IsNullOrEmpty(item.ServerName))
{
var sni = e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions["server_name"];
e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions["server_name"] =
new Titanium.Web.Proxy.StreamExtended.Models.SslExtension(sni.Value, sni.Name, item.ServerName, sni.Position);
}
else
{
e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions.Remove("server_name");
}
}
return;
}
}
}
exit:
//部分运营商将奇怪的域名解析到127.0.0.1 再此排除这些不支持的代理域名
if (IPAddress.IsLoopback(e.ClientRemoteEndPoint.Address))
{
var ip = (await DnsAnalysis.AnalysisDomainIpByAliDns(e.HttpClient.Request.Host))?.First();
if (ip == null || IPAddress.IsLoopback(ip))
{
e.TerminateSession();
Log.Info("Proxy", "IsLoopback OnRequest: " + e.HttpClient.Request.RequestUri.AbsoluteUri);
}
else
{
e.HttpClient.UpStreamEndPoint = new IPEndPoint(ip, e.ClientRemoteEndPoint.Port);
}
}
return;
}
private async Task OnResponse(object sender, SessionEventArgs e)
{
#if DEBUG
Debug.WriteLine("OnResponse" + e.HttpClient.Request.RequestUri.AbsoluteUri);
Log.Info("Proxy", "OnResponse" + e.HttpClient.Request.RequestUri.AbsoluteUri);
#endif
if (Scripts is null)
{
return;
}
if (IsEnableScript &&
e.HttpClient.Request.Method == "GET" &&
e.HttpClient.Response.StatusCode == 200 &&
e.HttpClient.Response.ContentType?.Contains("text/html", StringComparison.OrdinalIgnoreCase) == true)
{
if (IsOnlyWorkSteamBrowser)
{
var ua = e.HttpClient.Request.Headers.GetHeaders("User-Agent");
if (ua.FirstOrDefault()?.Value.Contains("Valve Steam") == false)
{
return;
}
}
StringBuilder scriptHtml = new StringBuilder();
foreach (var script in Scripts)
{
if (script.ExcludeDomainNamesArray != null)
foreach (var host in script.ExcludeDomainNamesArray)
{
if (e.HttpClient.Request.RequestUri.AbsoluteUri.IsWildcard(host))
goto next;
}
foreach (var host in script.MatchDomainNamesArray)
{
var state = host.IndexOf("/") == 0;
if (state)
state = Regex.IsMatch(e.HttpClient.Request.RequestUri.AbsoluteUri, host.Substring(1), RegexOptions.Compiled);
else
state = e.HttpClient.Request.RequestUri.AbsoluteUri.IsWildcard(host);
if (state)
{
var t = e.HttpClient.Response.Headers.GetFirstHeader("Content-Security-Policy");
if (!string.IsNullOrEmpty(t?.Value))
{
e.HttpClient.Response.Headers.RemoveHeader(t);
}
if (script.JsPathUrl == null)
script.JsPathUrl = $"/{Guid.NewGuid()}";
var temp = $"<script type=\"text/javascript\" src=\"https://local.steampp.net{script.JsPathUrl}\"></script>";
scriptHtml.AppendLine(temp);
}
}
next:;
}
if (scriptHtml.Length > 0)
{
var doc = await e.GetResponseBodyAsString();
var index = doc.LastIndexOf("</body>", StringComparison.OrdinalIgnoreCase);
if (index == -1)
index = doc.LastIndexOf("</head>", StringComparison.OrdinalIgnoreCase);
if (index > -1)
{
doc = doc.Insert(index, scriptHtml.ToString());
e.SetResponseBodyString(doc);
}
}
}
}
// 允许重写默认的证书验证逻辑
private static Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{
// 根据证书错误,设置IsValid为真/假
//if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
e.IsValid = true;
return Task.CompletedTask;
}
// 允许在相互身份验证期间重写默认客户端证书选择逻辑
private static Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{
// set e.clientCertificate to override
return Task.CompletedTask;
}
public void TrustCer()
{
var filePath = Path.Combine(IOPath.AppDataDirectory, $@"{CertificateName}.Certificate.cer");
IPlatformService.Instance.RunShell($"security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain \"{filePath}\"", true);
}
public bool SetupCertificate()
{
// 此代理使用的本地信任根证书
//proxyServer.CertificateManager.TrustRootCertificate(true);
//proxyServer.CertificateManager
// .CreateServerCertificate($"{Assembly.GetCallingAssembly().GetName().Name} Certificate")
// .ContinueWith(c => proxyServer.CertificateManager.RootCertificate = c.Result);
var result = proxyServer.CertificateManager.CreateRootCertificate(true);
if (!result || proxyServer.CertificateManager.RootCertificate == null)
{
Log.Error("Proxy", AppResources.CreateCertificateFaild);
Toast.Show(AppResources.CreateCertificateFaild);
return false;
}
var filePath = Path.Combine(IOPath.AppDataDirectory, $@"{CertificateName}.Certificate.cer");
proxyServer.CertificateManager.RootCertificate.SaveCerCertificateFile(filePath);
try
{
proxyServer.CertificateManager.TrustRootCertificate();
}
catch { }
try
{
proxyServer.CertificateManager.EnsureRootCertificate();
}
catch { }
if (OperatingSystem2.IsMacOS)
{
TrustCer();
}
if (OperatingSystem2.IsLinux)
{
//IPlatformService.Instance.AdminShell($"sudo cp -f \"{filePath}\" \"{Path.Combine(IOPath.AppDataDirectory, $@"{CertificateName}.Certificate.pem")}\"", false);
Browser2.Open(UrlConstants.OfficialWebsite_LiunxSetupCer);
return true;
}
return IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate);
}
public bool DeleteCertificate()
{
if (ProxyRunning)
return false;
try
{
//using (var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
//{
// store.Open(OpenFlags.MaxAllowed);
// var test = store.Certificates.Find(X509FindType.FindByIssuerName, CertificateName, true);
// foreach (var item in test)
// {
// store.Remove(item);
// }
//}
//proxyServer.CertificateManager.ClearRootCertificate();
proxyServer.CertificateManager.RemoveTrustedRootCertificate();
if (IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate) == false)
{
proxyServer.CertificateManager.RootCertificate = null;
if (File.Exists(proxyServer.CertificateManager.PfxFilePath))
File.Delete(proxyServer.CertificateManager.PfxFilePath);
}
//proxyServer.CertificateManager.RemoveTrustedRootCertificateAsAdmin();
//proxyServer.CertificateManager.CertificateStorage.Clear();
}
catch (CryptographicException)
{
//取消删除证书
}
catch (Exception ex)
{
throw ex;
}
return true;
}
public int GetRandomUnusedPort() => SocketHelper.GetRandomUnusedPort(ProxyIp);
public bool PortInUse(int port) => SocketHelper.IsUsePort(port);
public bool StartProxy()
{
if (OperatingSystem2.IsLinux)
{
var filePath = Path.Combine(IOPath.AppDataDirectory, $@"{CertificateName}.Certificate.cer");
if (!new FileInfo(filePath).Exists)
{
var isOk = SetupCertificate();
if (!isOk)
{
return false;
}
}
}
else
{
if (!IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate))
{
DeleteCertificate();
var isOk = SetupCertificate();
if (!isOk)
{
return false;
}
}
}
//else
//{
// SetupCertificate();
//}
#region 启动代理
proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
//proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
try
{
var explicitProxyEndPoint = new ExplicitProxyEndPoint(ProxyIp, GetRandomUnusedPort(), true)
{
// 通过不启用为每个http的域创建证书来优化性能
//GenericCertificate = proxyServer.CertificateManager.RootCertificate
};
explicitProxyEndPoint.BeforeTunnelConnectRequest += ExplicitProxyEndPoint_BeforeTunnelConnectRequest;
if (IsSystemProxy)
{
//explicit endpoint 是客户端知道代理存在的地方
proxyServer.AddEndPoint(explicitProxyEndPoint);
}
else
{
//if (PortInUse(443))
//{
// return false;
//}
TransparentProxyEndPoint transparentProxyEndPoint;
if (OperatingSystem2.IsLinux && !platformService.IsAdministrator)
{
var freeport = GetRandomUnusedPort();
transparentProxyEndPoint = new TransparentProxyEndPoint(ProxyIp, freeport, true)
{
// 通过不启用为每个http的域创建证书来优化性能
//GenericCertificate = proxyServer.CertificateManager.RootCertificate
};
Browser2.Open(string.Format(UrlConstants.OfficialWebsite_UnixHostAccess_, freeport));
}
else
{
transparentProxyEndPoint = new TransparentProxyEndPoint(ProxyIp, 443, true)
{
// 通过不启用为每个http的域创建证书来优化性能
//GenericCertificate = proxyServer.CertificateManager.RootCertificate
};
}
//transparentProxyEndPoint.BeforeSslAuthenticate += TransparentProxyEndPoint_BeforeSslAuthenticate;
proxyServer.AddEndPoint(transparentProxyEndPoint);
try
{
if (!OperatingSystem2.IsLinux)
{
if (PortInUse(80) == false)
proxyServer.AddEndPoint(new TransparentProxyEndPoint(ProxyIp, 80, false));
}
}
catch { }
}
if (Socks5ProxyEnable)
{
proxyServer.AddEndPoint(new SocksProxyEndPoint(ProxyIp, Socks5ProxyPortId, true));
}
if (TwoLevelAgentEnable && TwoLevelAgentIp != null)
{
proxyServer.UpStreamHttpsProxy = new ExternalProxy(TwoLevelAgentIp, TwoLevelAgentPortId)
{
ProxyDnsRequests = true,
BypassLocalhost = true,
ProxyType = TwoLevelAgentProxyType,
UserName = TwoLevelAgentUserName,
Password = TwoLevelAgentPassword,
};
proxyServer.ForwardToUpstreamGateway = true;
}
proxyServer.Start();
if (IsSystemProxy)
{
if (!DesktopBridge.IsRunningAsUwp && OperatingSystem2.IsWindows)
{
proxyServer.SetAsSystemProxy(explicitProxyEndPoint, ProxyProtocolType.AllHttp);
}
else
{
if (!IPlatformService.Instance.SetAsSystemProxy(true, explicitProxyEndPoint.IpAddress, explicitProxyEndPoint.Port))
{
Log.Error("Proxy", "系统代理开启失败");
return false;
}
}
}
if (IsProxyGOG) { WirtePemCertificateToGoGSteamPlugins(); }
}
catch (Exception ex)
{
Log.Error("Proxy", ex, nameof(StartProxy));
return false;
}
#endregion
#if DEBUG
foreach (var endPoint in proxyServer.ProxyEndPoints)
Debug.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
#endif
return true;
}
private Task TransparentProxyEndPoint_BeforeSslAuthenticate(object sender, BeforeSslAuthenticateEventArgs e)
{
e.DecryptSsl = false;
if (e.SniHostName.Contains(IHttpProxyService.LocalDomain, StringComparison.OrdinalIgnoreCase))
{
e.DecryptSsl = true;
return Task.CompletedTask;
}
if (ProxyDomains is null)
{
return Task.CompletedTask;
}
foreach (var item in ProxyDomains)
{
foreach (var host in item.DomainNamesArray)
{
if (e.SniHostName.Contains(new Uri("https://" + host).Host))
{
e.DecryptSsl = true;
return Task.CompletedTask;
}
}
}
//var ip = Dns.GetHostAddresses(e.SniHostName).FirstOrDefault();
//if (IPAddress.IsLoopback(ip))
//{
// e.TerminateSession();
// return Task.CompletedTask;
//}
return Task.CompletedTask;
}
private Task ExplicitProxyEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
e.DecryptSsl = false;
if (ProxyDomains is null || e.HttpClient?.Request?.Host == null)
{
return Task.CompletedTask;
}
if (e.HttpClient.Request.Host.Contains(IHttpProxyService.LocalDomain, StringComparison.OrdinalIgnoreCase))
{
e.DecryptSsl = true;
return Task.CompletedTask;
}
foreach (var item in ProxyDomains)
{
foreach (var host in item.DomainNamesArray)
{
if (e.HttpClient.Request.Url.Contains(host))
{
e.DecryptSsl = true;
return Task.CompletedTask;
}
}
}
//var ip = Dns.GetHostAddresses(e.HttpClient.Request.Host).FirstOrDefault();
//if (IPAddress.IsLoopback(ip))
//{
// e.TerminateSession();
// return Task.CompletedTask;
//}
return Task.CompletedTask;
}
public void StopProxy()
{
try
{
if (proxyServer.ProxyRunning)
{
proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse;
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
proxyServer.Stop();
}
if (IsSystemProxy)
{
if (DesktopBridge.IsRunningAsUwp || !OperatingSystem2.IsWindows)
{
IPlatformService.Instance.SetAsSystemProxy(false);
}
else
{
proxyServer.DisableAllSystemProxies();
}
}
}
catch (Exception ex)
{
Toast.Show(ex, nameof(HttpProxyServiceImpl), msg: nameof(StopProxy));
}
}
public bool WirtePemCertificateToGoGSteamPlugins()
{
var local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var gogPlugins = Path.Combine(local, "GOG.com", "Galaxy", "plugins", "installed");
if (Directory.Exists(gogPlugins))
{
foreach (var dir in Directory.GetDirectories(gogPlugins))
{
if (dir.Contains("steam"))
{
var pem = proxyServer.CertificateManager.RootCertificate!.
GetPublicPemCertificateString();
var certifi = Path.Combine(local, dir, "certifi", "cacert.pem");
if (File.Exists(certifi))
{
var file = File.ReadAllText(certifi);
var s = file.Substring(Constants.CERTIFICATE_TAG, Constants.CERTIFICATE_TAG, true);
if (string.IsNullOrEmpty(s))
{
File.AppendAllText(certifi, Environment.NewLine + pem);
}
else if (s.Trim() != pem.Trim())
{
var index = file.IndexOf(Constants.CERTIFICATE_TAG);
File.WriteAllText(certifi, file.Remove(index, s.Length) + pem);
}
return true;
}
}
}
}
return false;
}
public bool IsCertificateInstalled(X509Certificate2? certificate2)
{
if (certificate2 == null)
return false;
if (certificate2.NotAfter <= DateTime.Now)
return false;
using var store = new X509Store(OperatingSystem2.IsMacOS ? StoreName.My : StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
return store.Certificates.Contains(certificate2);
}
public void Dispose()
{
if (proxyServer.ProxyRunning)
{
StopProxy();
}
proxyServer.Dispose();
}
}
}