Unverified Commit 63ce4b3d authored by honfika's avatar honfika Committed by GitHub

Merge pull request #376 from justcoding121/develop

Beta
parents e817f10c f11b6b60
...@@ -170,18 +170,18 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -170,18 +170,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
//requestBodyHistory[e.Id] = bodyString; //requestBodyHistory[e.Id] = bodyString;
} }
////To cancel a request with a custom HTML content //To cancel a request with a custom HTML content
////Filter URL //Filter URL
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
//{ {
// await e.Ok("<!DOCTYPE html>" + await e.Ok("<!DOCTYPE html>" +
// "<html><body><h1>" + "<html><body><h1>" +
// "Website Blocked" + "Website Blocked" +
// "</h1>" + "</h1>" +
// "<p>Blocked by titanium web proxy.</p>" + "<p>Blocked by titanium web proxy.</p>" +
// "</body>" + "</body>" +
// "</html>"); "</html>");
//} }
////Redirect example ////Redirect example
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) //if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private int lastSessionNumber; private int lastSessionNumber;
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>(); public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public SessionListItem SelectedSession public SessionListItem SelectedSession
{ {
...@@ -63,10 +63,35 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -63,10 +63,35 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//proxyServer.CertificateEngine = CertificateEngine.DefaultWindows; //proxyServer.CertificateEngine = CertificateEngine.DefaultWindows;
////Set a password for the .pfx file
//proxyServer.PfxPassword = "PfxPassword";
////Set Name(path) of the Root certificate file
//proxyServer.PfxFilePath = @"C:\NameFolder\rootCert.pfx";
////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true
//proxyServer.OverwritePfxFile = true;
////save all fake certificates in folder "crts"(will be created in proxy dll directory)
////if create new Root certificate file(.pfx) ====> delete folder "crts"
//proxyServer.SaveFakeCertificates = true;
//Trust Root Certificate
proxyServer.TrustRootCertificate = true; proxyServer.TrustRootCertificate = true;
proxyServer.CertificateManager.TrustRootCertificateAsAdministrator(); proxyServer.TrustRootCertificateAsAdministrator = true;
proxyServer.ForwardToUpstreamGateway = true; proxyServer.ForwardToUpstreamGateway = true;
////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
//proxyServer.EnsureRootCertificate(true);
////or load directly certificate(As Administrator if need this)
////and At the same time chose path and password
////if password is incorrect and (overwriteRootCert=true)(RootCertificate=null) ====> replace an existing .pfx file
////note : load now (if existed)
//proxyServer.CertificateManager.LoadRootCertificate(@"C:\NameFolder\rootCert.pfx", "PfxPassword");
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{ {
ExcludedHttpsHostNameRegex = new[] { "ssllabs.com" }, ExcludedHttpsHostNameRegex = new[] { "ssllabs.com" },
......
...@@ -29,11 +29,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -29,11 +29,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
private readonly int bufferSize; private readonly int bufferSize;
/// <summary>
/// Holds a reference to proxy response handler method
/// </summary>
private Func<SessionEventArgs, Task> httpResponseHandler;
private readonly Action<Exception> exceptionFunc; private readonly Action<Exception> exceptionFunc;
/// <summary> /// <summary>
...@@ -108,11 +103,9 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -108,11 +103,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
internal SessionEventArgs(int bufferSize, internal SessionEventArgs(int bufferSize,
ProxyEndPoint endPoint, ProxyEndPoint endPoint,
Func<SessionEventArgs, Task> httpResponseHandler,
Action<Exception> exceptionFunc) Action<Exception> exceptionFunc)
{ {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
this.httpResponseHandler = httpResponseHandler;
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
ProxyClient = new ProxyClient(); ProxyClient = new ProxyClient();
...@@ -536,16 +529,18 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -536,16 +529,18 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
/// <param name="html"></param> /// <param name="html"></param>
/// <param name="headers"></param> /// <param name="headers"></param>
public async Task Ok(string html, Dictionary<string, HttpHeader> headers) public async Task Ok(string html, Dictionary<string, HttpHeader> headers = null)
{ {
var response = new OkResponse(); var response = new OkResponse();
response.Headers.AddHeaders(headers); if (headers != null)
{
response.Headers.AddHeaders(headers);
}
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Body = response.Encoding.GetBytes(html ?? string.Empty); response.Body = response.Encoding.GetBytes(html ?? string.Empty);
await Respond(response); await Respond(response);
WebSession.Request.CancelRequest = true;
} }
/// <summary> /// <summary>
...@@ -635,8 +630,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -635,8 +630,6 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response = response; WebSession.Response = response;
await httpResponseHandler(this);
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
...@@ -645,7 +638,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -645,7 +638,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
httpResponseHandler = null;
CustomUpStreamProxyUsed = null; CustomUpStreamProxyUsed = null;
DataSent = null; DataSent = null;
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.EventArguments
public bool IsHttpsConnect { get; set; } public bool IsHttpsConnect { get; set; }
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, Action<Exception> exceptionFunc) internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, Action<Exception> exceptionFunc)
: base(bufferSize, endPoint, null, exceptionFunc) : base(bufferSize, endPoint, exceptionFunc)
{ {
WebSession.Request = connectRequest; WebSession.Request = connectRequest;
} }
......
using System; using System;
using System.IO; using System.IO;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.Pkcs;
...@@ -24,6 +25,8 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -24,6 +25,8 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// </summary> /// </summary>
internal class BCCertificateMaker : ICertificateMaker internal class BCCertificateMaker : ICertificateMaker
{ {
public static readonly Regex CNRemoverRegex = new Regex(@"^CN\s*=\s*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private const int certificateValidDays = 1825; private const int certificateValidDays = 1825;
private const int certificateGraceDays = 366; private const int certificateGraceDays = 366;
...@@ -146,7 +149,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -146,7 +149,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
{ {
try try
{ {
x509Certificate.FriendlyName = subjectName; x509Certificate.FriendlyName = CNRemoverRegex.Replace(subjectName, string.Empty);
} }
catch (PlatformNotSupportedException) catch (PlatformNotSupportedException)
{ {
......
...@@ -88,10 +88,10 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -88,10 +88,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
{ {
string httpStatus = await reader.ReadLineAsync(); string httpStatus = await reader.ReadLineAsync();
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);
if (!statusDescription.EqualsIgnoreCase("200 OK") if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK")
&& !statusDescription.EqualsIgnoreCase("connection established")) && !statusDescription.EqualsIgnoreCase("Connection Established"))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
......
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="tcpRows">TcpRow collection to initialize with.</param> /// <param name="tcpRows">TcpRow collection to initialize with.</param>
internal TcpTable(IEnumerable<TcpRow> tcpRows) internal TcpTable(IEnumerable<TcpRow> tcpRows)
{ {
this.TcpRows = tcpRows; TcpRows = tcpRows;
} }
/// <summary> /// <summary>
......
using StreamExtended.Network; using StreamExtended.Network;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
...@@ -37,11 +37,6 @@ namespace Titanium.Web.Proxy ...@@ -37,11 +37,6 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private Action<Exception> exceptionFunc; private Action<Exception> exceptionFunc;
/// <summary>
/// Backing field for corresponding public property
/// </summary>
private bool trustRootCertificate;
/// <summary> /// <summary>
/// Backing field for corresponding public property /// Backing field for corresponding public property
/// </summary> /// </summary>
...@@ -52,6 +47,8 @@ namespace Titanium.Web.Proxy ...@@ -52,6 +47,8 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private int serverConnectionCount; private int serverConnectionCount;
private X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable;
/// <summary> /// <summary>
/// A object that creates tcp connection to server /// A object that creates tcp connection to server
/// </summary> /// </summary>
...@@ -102,7 +99,7 @@ namespace Titanium.Web.Proxy ...@@ -102,7 +99,7 @@ namespace Titanium.Web.Proxy
/// Name of the root certificate /// Name of the root certificate
/// (This is valid only when RootCertificate property is not set) /// (This is valid only when RootCertificate property is not set)
/// If no certificate is provided then a default Root Certificate will be created and used /// If no certificate is provided then a default Root Certificate will be created and used
/// The provided root certificate will be stored in proxy exe directory with the private key /// The provided root certificate will be stored in proxy exe directory with the private key
/// Root certificate file will be named as "rootCert.pfx" /// Root certificate file will be named as "rootCert.pfx"
/// </summary> /// </summary>
public string RootCertificateName public string RootCertificateName
...@@ -118,14 +115,64 @@ namespace Titanium.Web.Proxy ...@@ -118,14 +115,64 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public bool TrustRootCertificate public bool TrustRootCertificate
{ {
get => trustRootCertificate; get => CertificateManager.trustRootCertificate;
set => CertificateManager.trustRootCertificate = value;
}
/// <summary>
/// Needs elevated permission. Works only on Windows.
/// <para>Puts the certificate to the local machine's certificate store.</para>
/// <para>Certutil.exe is a command-line program that is installed as part of Certificate Services</para>
/// </summary>
public bool TrustRootCertificateAsAdministrator { get; set; } = false;
/// <summary>
/// Save all fake certificates in folder "crts"(will be created in proxy dll directory)
/// <para>for can load the certificate and not make new certificate every time </para>
/// </summary>
public bool SaveFakeCertificates
{
get => CertificateManager.SaveFakeCertificates;
set => CertificateManager.SaveFakeCertificates = value;
}
/// <summary>
/// Overwrite Root certificate file
/// <para>true : replace an existing .pfx file if password is incorect or if RootCertificate = null</para>
/// </summary>
public bool OverwritePfxFile
{
get => CertificateManager.OverwritePfXFile;
set => CertificateManager.OverwritePfXFile = value;
}
/// <summary>
/// Password of the Root certificate file
/// <para>Set a password for the .pfx file</para>
/// </summary>
public string PfxPassword
{
get => CertificateManager.PfxPassword;
set => CertificateManager.PfxPassword = value;
}
/// <summary>
/// Name(path) of the Root certificate file
/// <para>Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as "rootCert.pfx" (and will be saved in proxy dll directory)</para>
/// </summary>
public string PfxFilePath
{
get => CertificateManager.PfxFilePath;
set => CertificateManager.PfxFilePath = value;
}
public X509KeyStorageFlags StorageFlag
{
get => storageFlag;
set set
{ {
trustRootCertificate = value; storageFlag = value;
if (value) CertificateManager.StorageFlag = storageFlag;
{
EnsureRootCertificate();
}
} }
} }
...@@ -346,7 +393,7 @@ namespace Titanium.Web.Proxy ...@@ -346,7 +393,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Remove a proxy end point /// Remove a proxy end point
/// Will throw error if the end point does'nt exist /// Will throw error if the end point does'nt exist
/// </summary> /// </summary>
/// <param name="endPoint"></param> /// <param name="endPoint"></param>
public void RemoveEndPoint(ProxyEndPoint endPoint) public void RemoveEndPoint(ProxyEndPoint endPoint)
...@@ -373,7 +420,6 @@ namespace Titanium.Web.Proxy ...@@ -373,7 +420,6 @@ namespace Titanium.Web.Proxy
SetAsSystemProxy(endPoint, ProxyProtocolType.Http); SetAsSystemProxy(endPoint, ProxyProtocolType.Http);
} }
/// <summary> /// <summary>
/// Set the given explicit end point as the default proxy server for current machine /// Set the given explicit end point as the default proxy server for current machine
/// </summary> /// </summary>
...@@ -520,6 +566,11 @@ namespace Titanium.Web.Proxy ...@@ -520,6 +566,11 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is already running."); throw new Exception("Proxy is already running.");
} }
if (ProxyEndPoints.OfType<ExplicitProxyEndPoint>().Any(x => x.GenericCertificate == null))
{
EnsureRootCertificate();
}
//clear any system proxy settings which is pointing to our own endpoint (causing a cycle) //clear any system proxy settings which is pointing to our own endpoint (causing a cycle)
//due to non gracious proxy shutdown before or something else //due to non gracious proxy shutdown before or something else
if (systemProxySettingsManager != null && RunTime.IsWindows) if (systemProxySettingsManager != null && RunTime.IsWindows)
...@@ -571,7 +622,6 @@ namespace Titanium.Web.Proxy ...@@ -571,7 +622,6 @@ namespace Titanium.Web.Proxy
} }
} }
/// <summary> /// <summary>
/// Stop this proxy server /// Stop this proxy server
/// </summary> /// </summary>
...@@ -604,26 +654,6 @@ namespace Titanium.Web.Proxy ...@@ -604,26 +654,6 @@ namespace Titanium.Web.Proxy
ProxyRunning = false; ProxyRunning = false;
} }
/// <summary>
/// Handle dispose of a client/server session
/// </summary>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="serverConnection"></param>
private void Dispose(CustomBufferedStream clientStream, CustomBinaryReader clientStreamReader, HttpResponseWriter clientStreamWriter, TcpConnection serverConnection)
{
clientStreamReader?.Dispose();
clientStream?.Dispose();
if (serverConnection != null)
{
serverConnection.Dispose();
serverConnection = null;
}
}
/// <summary> /// <summary>
/// Dispose Proxy. /// Dispose Proxy.
/// </summary> /// </summary>
...@@ -692,7 +722,17 @@ namespace Titanium.Web.Proxy ...@@ -692,7 +722,17 @@ namespace Titanium.Web.Proxy
return Task.FromResult(proxy); return Task.FromResult(proxy);
} }
private void EnsureRootCertificate() /// <summary>
/// Load or Create Certificate : after "Test Is the root certificate used by this proxy is valid?"
/// <param name="trustRootCertificate">"Make current machine trust the Root Certificate used by this proxy" ==> True or False</param>
/// </summary>
public void EnsureRootCertificate(bool trustRootCertificate)
{
TrustRootCertificate = trustRootCertificate;
EnsureRootCertificate();
}
public void EnsureRootCertificate()
{ {
if (!CertificateManager.CertValidated) if (!CertificateManager.CertValidated)
{ {
...@@ -702,6 +742,11 @@ namespace Titanium.Web.Proxy ...@@ -702,6 +742,11 @@ namespace Titanium.Web.Proxy
{ {
CertificateManager.TrustRootCertificate(); CertificateManager.TrustRootCertificate();
} }
if (TrustRootCertificateAsAdministrator)
{
CertificateManager.TrustRootCertificateAsAdministrator();
}
} }
} }
...@@ -753,13 +798,13 @@ namespace Titanium.Web.Proxy ...@@ -753,13 +798,13 @@ namespace Titanium.Web.Proxy
try try
{ {
if (endPoint.GetType() == typeof(TransparentProxyEndPoint)) if (endPoint is TransparentProxyEndPoint tep)
{ {
await HandleClient(endPoint as TransparentProxyEndPoint, tcpClient); await HandleClient(tep, tcpClient);
} }
else else
{ {
await HandleClient(endPoint as ExplicitProxyEndPoint, tcpClient); await HandleClient((ExplicitProxyEndPoint)endPoint, tcpClient);
} }
} }
finally finally
......
This diff is collapsed.
...@@ -18,7 +18,7 @@ namespace Titanium.Web.Proxy ...@@ -18,7 +18,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
/// <returns>true if client/server connection was terminated (and disposed) </returns> /// <returns>true if client/server connection was terminated (and disposed) </returns>
private async Task<bool> HandleHttpSessionResponse(SessionEventArgs args) private async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
try try
{ {
...@@ -30,12 +30,7 @@ namespace Titanium.Web.Proxy ...@@ -30,12 +30,7 @@ namespace Titanium.Web.Proxy
//check for windows authentication //check for windows authentication
if (isWindowsAuthenticationEnabledAndSupported && response.StatusCode == (int)HttpStatusCode.Unauthorized) if (isWindowsAuthenticationEnabledAndSupported && response.StatusCode == (int)HttpStatusCode.Unauthorized)
{ {
bool disposed = await Handle401UnAuthorized(args); await Handle401UnAuthorized(args);
if (disposed)
{
return true;
}
} }
args.ReRequest = false; args.ReRequest = false;
...@@ -52,8 +47,8 @@ namespace Titanium.Web.Proxy ...@@ -52,8 +47,8 @@ namespace Titanium.Web.Proxy
{ {
//clear current response //clear current response
await args.ClearResponse(); await args.ClearResponse();
bool disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false); await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
return disposed; return;
} }
response.ResponseLocked = true; response.ResponseLocked = true;
...@@ -109,16 +104,10 @@ namespace Titanium.Web.Proxy ...@@ -109,16 +104,10 @@ namespace Titanium.Web.Proxy
} }
} }
} }
catch (Exception e) catch (Exception e) when (!(e is ProxyHttpException))
{ {
ExceptionFunc(new ProxyHttpException("Error occured whilst handling session response", e, args)); throw new ProxyHttpException("Error occured whilst handling session response", e, args);
Dispose(args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamReader, args.ProxyClient.ClientStreamWriter,
args.WebSession.ServerConnection);
return true;
} }
return false;
} }
/// <summary> /// <summary>
......
...@@ -135,8 +135,7 @@ namespace Titanium.Web.Proxy ...@@ -135,8 +135,7 @@ namespace Titanium.Web.Proxy
//request again with updated authorization header //request again with updated authorization header
//and server cookies //and server cookies
bool disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false); await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
return disposed;
} }
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment