Commit a988e27d authored by justcoding121's avatar justcoding121

Merge branch 'develop' into beta

parents f2817483 1ce0f7fa
...@@ -32,20 +32,18 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -32,20 +32,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//generate root certificate without storing it in file system //generate root certificate without storing it in file system
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//proxyServer.CertificateManager.CreateTrustedRootCertificate(false); //proxyServer.CertificateManager.CreateTrustedRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate(); //proxyServer.CertificateManager.TrustRootCertificate();
proxyServer.ExceptionFunc = exception => Console.WriteLine(exception.Message); proxyServer.ExceptionFunc = exception => Console.WriteLine(exception.Message);
proxyServer.TrustRootCertificate = true;
proxyServer.ForwardToUpstreamGateway = true; proxyServer.ForwardToUpstreamGateway = true;
//optionally set the Certificate Engine //optionally set the Certificate Engine
//Under Mono or Non-Windows runtimes only BouncyCastle will be supported //Under Mono or Non-Windows runtimes only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.DefaultWindows; //proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//optionally set the Root Certificate //optionally set the Root Certificate
//proxyServer.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable); //proxyServer.CertificateManager.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
} }
public void StartProxy() public void StartProxy()
...@@ -68,9 +66,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -68,9 +66,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
}; };
//Exclude Https addresses you don't want to proxy //Fired when a CONNECT request is received
//Useful for clients that use certificate pinning
//for example google.com and dropbox.com
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect; explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
...@@ -130,10 +126,11 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -130,10 +126,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task<bool> OnBeforeTunnelConnect(string hostname) private async Task<bool> OnBeforeTunnelConnect(string hostname)
{ {
if (hostname.Contains("amazon.com") || hostname.Contains("paypal.com")) if (hostname.Contains("dropbox.com"))
{ {
//exclude bing.com and google.com from being decrypted //Exclude Https addresses you don't want to proxy
//instead it will be relayed via a secure TCP tunnel //Useful for clients that use certificate pinning
//for example dropbox.com
return await Task.FromResult(true); return await Task.FromResult(true);
} }
else else
...@@ -183,7 +180,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -183,7 +180,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Filter URL //Filter URL
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com"))
{ {
await e.Ok("<!DOCTYPE html>" + e.Ok("<!DOCTYPE html>" +
"<html><body><h1>" + "<html><body><h1>" +
"Website Blocked" + "Website Blocked" +
"</h1>" + "</h1>" +
...@@ -195,7 +192,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -195,7 +192,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
////Redirect example ////Redirect example
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) //if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
//{ //{
// await e.Redirect("https://www.paypal.com"); // e.Redirect("https://www.paypal.com");
//} //}
} }
......
...@@ -62,29 +62,25 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -62,29 +62,25 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public MainWindow() public MainWindow()
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//proxyServer.CertificateEngine = CertificateEngine.DefaultWindows; //proxyServer.CertificateManager.CertificateEngine = CertificateEngine.DefaultWindows;
////Set a password for the .pfx file ////Set a password for the .pfx file
//proxyServer.PfxPassword = "PfxPassword"; //proxyServer.CertificateManager.PfxPassword = "PfxPassword";
////Set Name(path) of the Root certificate file ////Set Name(path) of the Root certificate file
//proxyServer.PfxFilePath = @"C:\NameFolder\rootCert.pfx"; //proxyServer.CertificateManager.PfxFilePath = @"C:\NameFolder\rootCert.pfx";
////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true ////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true
//proxyServer.OverwritePfxFile = true; //proxyServer.CertificateManager.OverwritePfxFile = true;
////save all fake certificates in folder "crts"(will be created in proxy dll directory) ////save all fake certificates in folder "crts"(will be created in proxy dll directory)
////if create new Root certificate file(.pfx) ====> delete folder "crts" ////if create new Root certificate file(.pfx) ====> delete folder "crts"
//proxyServer.SaveFakeCertificates = true; //proxyServer.CertificateManager.SaveFakeCertificates = true;
//Trust Root Certificate
proxyServer.TrustRootCertificate = true;
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 ////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
//proxyServer.EnsureRootCertificate(true); //proxyServer.CertificateManager.EnsureRootCertificate(true);
////or load directly certificate(As Administrator if need this) ////or load directly certificate(As Administrator if need this)
////and At the same time chose path and password ////and At the same time chose path and password
......
...@@ -52,11 +52,11 @@ Setup HTTP proxy: ...@@ -52,11 +52,11 @@ Setup HTTP proxy:
var proxyServer = new ProxyServer(); var proxyServer = new ProxyServer();
//locally trust root certificate used by this proxy //locally trust root certificate used by this proxy
proxyServer.TrustRootCertificate = true; proxyServer.CertificateManager.TrustRootCertificate = true;
//optionally set the Certificate Engine //optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported //Under Mono only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle; //proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse; proxyServer.BeforeResponse += OnResponse;
...@@ -66,17 +66,17 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; ...@@ -66,17 +66,17 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{ {
//Exclude HTTPS addresses you don't want to proxy //You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Useful for clients that use certificate pinning
//for example dropbox.com
// ExcludedHttpsHostNameRegex = new List<string>() { "google.com", "dropbox.com" }
//Use self-issued generic certificate on all HTTPS requests //Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each HTTPS-enabled domain //Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients //Useful when certificate trust is not required by proxy clients
// GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
}; };
//Fired when a CONNECT request is received
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
//An explicit endpoint is where the client knows about the existence of a proxy //An explicit endpoint is where the client knows about the existence of a proxy
//So client sends request in a proxy friendly manner //So client sends request in a proxy friendly manner
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
...@@ -109,6 +109,7 @@ proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); ...@@ -109,6 +109,7 @@ proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
Console.Read(); Console.Read();
//Unsubscribe & Quit //Unsubscribe & Quit
explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect;
proxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse; proxyServer.BeforeResponse -= OnResponse;
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation; proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
...@@ -125,6 +126,21 @@ Sample request and response event handlers ...@@ -125,6 +126,21 @@ Sample request and response event handlers
private IDictionary<Guid, string> requestBodyHistory private IDictionary<Guid, string> requestBodyHistory
= new ConcurrentDictionary<Guid, string>(); = new ConcurrentDictionary<Guid, string>();
private async Task<bool> OnBeforeTunnelConnect(string hostname)
{
if (hostname.Contains("dropbox.com"))
{
//Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning
//for example dropbox.com
return await Task.FromResult(true);
}
else
{
return await Task.FromResult(false);
}
}
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
Console.WriteLine(e.WebSession.Request.Url); Console.WriteLine(e.WebSession.Request.Url);
...@@ -152,7 +168,7 @@ public async Task OnRequest(object sender, SessionEventArgs e) ...@@ -152,7 +168,7 @@ public async Task OnRequest(object sender, SessionEventArgs e)
//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>" + e.Ok("<!DOCTYPE html>" +
"<html><body><h1>" + "<html><body><h1>" +
"Website Blocked" + "Website Blocked" +
"</h1>" + "</h1>" +
...@@ -163,7 +179,7 @@ public async Task OnRequest(object sender, SessionEventArgs e) ...@@ -163,7 +179,7 @@ public async Task OnRequest(object sender, SessionEventArgs e)
//Redirect example //Redirect example
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
{ {
await e.Redirect("https://www.paypal.com"); e.Redirect("https://www.paypal.com");
} }
} }
......
...@@ -51,7 +51,6 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -51,7 +51,6 @@ namespace Titanium.Web.Proxy.IntegrationTests
public ProxyTestController() public ProxyTestController()
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
proxyServer.TrustRootCertificate = true;
} }
public void StartProxy(int proxyPort) public void StartProxy(int proxyPort)
......
...@@ -15,28 +15,53 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -15,28 +15,53 @@ namespace Titanium.Web.Proxy.UnitTests
private readonly Random random = new Random(); private readonly Random random = new Random();
[TestMethod] [TestMethod]
public async Task Simple_Create_Certificate_Stress_Test() public async Task Simple_Create_Certificate_Test()
{ {
var tasks = new List<Task>(); var tasks = new List<Task>();
var mgr = new CertificateManager(new Lazy<Action<Exception>>(() => (e => { })).Value); var mgr = new CertificateManager(new Lazy<Action<Exception>>(() => (e => { })).Value);
mgr.ClearIdleCertificates(1); mgr.ClearIdleCertificates();
for (int i = 0; i < 1000; i++)
{
foreach (string host in hostNames) foreach (string host in hostNames)
{ {
tasks.Add(Task.Run(async () => tasks.Add(Task.Run(async () =>
{ {
await Task.Delay(random.Next(0, 10) * 1000);
//get the connection //get the connection
var certificate = mgr.CreateCertificate(host, false); var certificate = await mgr.CreateCertificateAsync(host);
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
})); }));
} }
await Task.WhenAll(tasks.ToArray());
mgr.StopClearIdleCertificates();
}
//uncomment this to compare WinCert maker performance with BC (BC takes more time for same test above)
//cannot run this test in build server since trusting the certificate won't happen successfully
//[TestMethod]
public async Task Simple_Create_Win_Certificate_Test()
{
var tasks = new List<Task>();
var mgr = new CertificateManager(new Lazy<Action<Exception>>(() => (e => { })).Value);
mgr.CreateRootCertificate(true);
mgr.TrustRootCertificate();
mgr.ClearIdleCertificates();
mgr.CertificateEngine = CertificateEngine.DefaultWindows;
foreach (string host in hostNames)
{
tasks.Add(Task.Run(async () =>
{
//get the connection
var certificate = await mgr.CreateCertificateAsync(host);
Assert.IsNotNull(certificate);
}));
} }
await Task.WhenAll(tasks.ToArray()); await Task.WhenAll(tasks.ToArray());
......
...@@ -531,7 +531,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -531,7 +531,7 @@ 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 = null) public void Ok(string html, Dictionary<string, HttpHeader> headers = null)
{ {
var response = new OkResponse(); var response = new OkResponse();
if (headers != null) if (headers != null)
...@@ -542,7 +542,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -542,7 +542,7 @@ namespace Titanium.Web.Proxy.EventArguments
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); Respond(response);
} }
/// <summary> /// <summary>
...@@ -552,14 +552,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -552,14 +552,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
/// <param name="result"></param> /// <param name="result"></param>
/// <param name="headers"></param> /// <param name="headers"></param>
public async Task Ok(byte[] result, Dictionary<string, HttpHeader> headers = null) public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null)
{ {
var response = new OkResponse(); var response = new OkResponse();
response.Headers.AddHeaders(headers); response.Headers.AddHeaders(headers);
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Body = result; response.Body = result;
await Respond(response); Respond(response);
} }
/// <summary> /// <summary>
...@@ -572,14 +572,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -572,14 +572,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="status"></param> /// <param name="status"></param>
/// <param name="headers"></param> /// <param name="headers"></param>
/// <returns></returns> /// <returns></returns>
public async Task GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null) public void GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null)
{ {
var response = new GenericResponse(status); var response = new GenericResponse(status);
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeaders(headers); response.Headers.AddHeaders(headers);
response.Body = response.Encoding.GetBytes(html ?? string.Empty); response.Body = response.Encoding.GetBytes(html ?? string.Empty);
await Respond(response); Respond(response);
} }
/// <summary> /// <summary>
...@@ -592,14 +592,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -592,14 +592,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="status"></param> /// <param name="status"></param>
/// <param name="headers"></param> /// <param name="headers"></param>
/// <returns></returns> /// <returns></returns>
public async Task GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers) public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers)
{ {
var response = new GenericResponse(status); var response = new GenericResponse(status);
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeaders(headers); response.Headers.AddHeaders(headers);
response.Body = result; response.Body = result;
await Respond(response); Respond(response);
} }
/// <summary> /// <summary>
...@@ -607,18 +607,18 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -607,18 +607,18 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
/// <returns></returns> /// <returns></returns>
public async Task Redirect(string url) public void Redirect(string url)
{ {
var response = new RedirectResponse(); var response = new RedirectResponse();
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeader(KnownHeaders.Location, url); response.Headers.AddHeader(KnownHeaders.Location, url);
response.Body = emptyData; response.Body = emptyData;
await Respond(response); Respond(response);
} }
/// a generic responder method /// a generic responder method
public async Task Respond(Response response) public void Respond(Response response)
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
{ {
......
This diff is collapsed.
...@@ -132,7 +132,7 @@ namespace Titanium.Web.Proxy ...@@ -132,7 +132,7 @@ namespace Titanium.Web.Proxy
string certName = HttpHelper.GetWildCardDomainName(connectHostname); string certName = HttpHelper.GetWildCardDomainName(connectHostname);
var certificate = endPoint.GenericCertificate ?? CertificateManager.CreateCertificate(certName, false); var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);
...@@ -252,7 +252,7 @@ namespace Titanium.Web.Proxy ...@@ -252,7 +252,7 @@ namespace Titanium.Web.Proxy
string sniHostName = clientHelloInfo.GetServerName(); string sniHostName = clientHelloInfo.GetServerName();
string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName); string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName);
var certificate = CertificateManager.CreateCertificate(certName, false); var certificate = await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.3" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.1.4" />
<PackageReference Include="StreamExtended" Version="1.0.135-beta" /> <PackageReference Include="StreamExtended" Version="1.0.135-beta" />
</ItemGroup> </ItemGroup>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<tags></tags> <tags></tags>
<dependencies> <dependencies>
<dependency id="StreamExtended" version="1.0.110-beta" /> <dependency id="StreamExtended" version="1.0.110-beta" />
<dependency id="Portable.BouncyCastle" version="1.8.1.3" /> <dependency id="Portable.BouncyCastle" version="1.8.1.4" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.1.3" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.1.4" targetFramework="net45" />
<package id="StreamExtended" version="1.0.110-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.110-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
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