Commit e928c25a authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #215 from justcoding121/develop

Beta merge
parents b62f9f14 e7b254f1
...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public class Program public class Program
{ {
private static readonly ProxyTestController Controller = new ProxyTestController(); private static readonly ProxyTestController controller = new ProxyTestController();
public static void Main(string[] args) public static void Main(string[] args)
{ {
...@@ -15,13 +15,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -15,13 +15,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Start proxy controller //Start proxy controller
Controller.StartProxy(); controller.StartProxy();
Console.WriteLine("Hit any key to exit.."); Console.WriteLine("Hit any key to exit..");
Console.WriteLine(); Console.WriteLine();
Console.Read(); Console.Read();
Controller.Stop(); controller.Stop();
} }
...@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
if (eventType != 2) return false; if (eventType != 2) return false;
try try
{ {
Controller.Stop(); controller.Stop();
} }
catch catch
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -9,10 +10,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -9,10 +10,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public class ProxyTestController public class ProxyTestController
{ {
private ProxyServer proxyServer; private readonly ProxyServer proxyServer;
//share requestBody outside handlers //share requestBody outside handlers
private Dictionary<Guid, string> requestBodyHistory; private readonly Dictionary<Guid, string> requestBodyHistory = new Dictionary<Guid, string>();
public ProxyTestController() public ProxyTestController()
{ {
...@@ -21,9 +22,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -21,9 +22,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
//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.CertificateEngine = Network.CertificateEngine.BouncyCastle;
requestBodyHistory = new Dictionary<Guid, string>(); //optionally set the Root Certificate
//proxyServer.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
} }
public void StartProxy() public void StartProxy()
......
...@@ -112,7 +112,7 @@ Sample request and response event handlers ...@@ -112,7 +112,7 @@ Sample request and response event handlers
```csharp ```csharp
//To access requestBody from OnResponse handler //To access requestBody from OnResponse handler
private Dictionary<Guid, string> requestBodyHistory; private Dictionary<Guid, string> requestBodyHistory = new Dictionary<Guid, string>();
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.UnitTests
[TestClass] [TestClass]
public class CertificateManagerTests public class CertificateManagerTests
{ {
private readonly static string[] hostNames private static readonly string[] hostNames
= new string[] { "facebook.com", "youtube.com", "google.com", = new string[] { "facebook.com", "youtube.com", "google.com",
"bing.com", "yahoo.com"}; "bing.com", "yahoo.com"};
......
...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy ...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal bool ValidateServerCertificate( private bool ValidateServerCertificate(
object sender, object sender,
X509Certificate certificate, X509Certificate certificate,
X509Chain chain, X509Chain chain,
...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy ...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param> /// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param> /// <param name="acceptableIssuers"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate( private X509Certificate SelectClientCertificate(
object sender, object sender,
string targetHost, string targetHost,
X509CertificateCollection localCertificates, X509CertificateCollection localCertificates,
......
...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <summary> /// <summary>
/// Extension methods for Byte Arrays. /// Extension methods for Byte Arrays.
/// </summary> /// </summary>
public static class ByteArrayExtensions internal static class ByteArrayExtensions
{ {
/// <summary> /// <summary>
/// Get the sub array from byte of data /// Get the sub array from byte of data
...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="length"></param> /// <param name="length"></param>
/// <returns></returns> /// <returns></returns>
public static T[] SubArray<T>(this T[] data, int index, int length) internal static T[] SubArray<T>(this T[] data, int index, int length)
{ {
var result = new T[length]; var result = new T[length];
Array.Copy(data, index, result, 0, length); Array.Copy(data, index, result, 0, length);
......
...@@ -6,12 +6,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -6,12 +6,12 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// A helper class to set proxy settings for firefox /// A helper class to set proxy settings for firefox
/// </summary> /// </summary>
public class FireFoxProxySettingsManager internal class FireFoxProxySettingsManager
{ {
/// <summary> /// <summary>
/// Add Firefox settings. /// Add Firefox settings.
/// </summary> /// </summary>
public void AddFirefox() internal void AddFirefox()
{ {
try try
{ {
...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Remove firefox settings. /// Remove firefox settings.
/// </summary> /// </summary>
public void RemoveFirefox() internal void RemoveFirefox()
{ {
try try
{ {
......
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets;
namespace Titanium.Web.Proxy.Helpers
{ namespace Titanium.Web.Proxy.Helpers
internal class NetworkHelper {
{ internal class NetworkHelper
private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion) {
{ private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion)
var tcpRow = TcpHelper.GetExtendedTcpTable(ipVersion).FirstOrDefault( {
row => row.LocalEndPoint.Port == port); var tcpRow = TcpHelper.GetExtendedTcpTable(ipVersion).FirstOrDefault(
row => row.LocalEndPoint.Port == port);
return tcpRow?.ProcessId ?? 0;
} return tcpRow?.ProcessId ?? 0;
}
internal static int GetProcessIdFromPort(int port, bool ipV6Enabled)
{ internal static int GetProcessIdFromPort(int port, bool ipV6Enabled)
var processId = FindProcessIdFromLocalPort(port, IpVersion.Ipv4); {
var processId = FindProcessIdFromLocalPort(port, IpVersion.Ipv4);
if (processId > 0 && !ipV6Enabled)
{ if (processId > 0 && !ipV6Enabled)
return processId; {
} return processId;
}
return FindProcessIdFromLocalPort(port, IpVersion.Ipv6);
} return FindProcessIdFromLocalPort(port, IpVersion.Ipv6);
}
/// <summary>
/// Adapated from below link /// <summary>
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost /// Adapated from below link
/// </summary> /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// <param name="address"></param> /// </summary>
/// <returns></returns> /// <param name="address"></param>
internal static bool IsLocalIpAddress(IPAddress address) /// <returns></returns>
{ internal static bool IsLocalIpAddress(IPAddress address)
// get local IP addresses {
var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); // get local IP addresses
// test if any host IP equals to any local IP or to localhost var localIPs = Dns.GetHostAddresses(Dns.GetHostName());
return IPAddress.IsLoopback(address) || localIPs.Contains(address); // test if any host IP equals to any local IP or to localhost
} return IPAddress.IsLoopback(address) || localIPs.Contains(address);
} }
}
internal static bool IsLocalIpAddress(string hostName)
{
bool isLocalhost = false;
IPHostEntry localhost = Dns.GetHostEntry("127.0.0.1");
if (hostName == localhost.HostName)
{
IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = hostEntry.AddressList.Any(IPAddress.IsLoopback);
}
if (!isLocalhost)
{
localhost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = null;
if (IPAddress.TryParse(hostName, out ipAddress))
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
if (!isLocalhost)
{
try
{
var hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = localhost.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals));
}
catch (SocketException)
{
}
}
}
return isLocalhost;
}
}
}
...@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint public class ExplicitProxyEndPoint : ProxyEndPoint
{ {
private List<string> _excludedHttpsHostNameRegex; private List<string> excludedHttpsHostNameRegex;
private List<string> _includedHttpsHostNameRegex; private List<string> includedHttpsHostNameRegex;
internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpProxy { get; set; }
...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public List<string> ExcludedHttpsHostNameRegex public List<string> ExcludedHttpsHostNameRegex
{ {
get { return _excludedHttpsHostNameRegex; } get { return excludedHttpsHostNameRegex; }
set set
{ {
if (IncludedHttpsHostNameRegex != null) if (IncludedHttpsHostNameRegex != null)
...@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Models
throw new ArgumentException("Cannot set excluded when included is set"); throw new ArgumentException("Cannot set excluded when included is set");
} }
_excludedHttpsHostNameRegex = value; excludedHttpsHostNameRegex = value;
} }
} }
...@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public List<string> IncludedHttpsHostNameRegex public List<string> IncludedHttpsHostNameRegex
{ {
get { return _includedHttpsHostNameRegex; } get { return includedHttpsHostNameRegex; }
set set
{ {
if (ExcludedHttpsHostNameRegex != null) if (ExcludedHttpsHostNameRegex != null)
...@@ -90,7 +90,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -90,7 +90,7 @@ namespace Titanium.Web.Proxy.Models
throw new ArgumentException("Cannot set included when excluded is set"); throw new ArgumentException("Cannot set included when excluded is set");
} }
_includedHttpsHostNameRegex = value; includedHttpsHostNameRegex = value;
} }
} }
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExternalProxy public class ExternalProxy
{ {
private static readonly Lazy<NetworkCredential> DefaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials); private static readonly Lazy<NetworkCredential> defaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials);
private string userName; private string userName;
private string password; private string password;
...@@ -18,16 +18,21 @@ namespace Titanium.Web.Proxy.Models ...@@ -18,16 +18,21 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public bool UseDefaultCredentials { get; set; } public bool UseDefaultCredentials { get; set; }
/// <summary>
/// Bypass this proxy for connections to localhost?
/// </summary>
public bool BypassForLocalhost { get; set; }
/// <summary> /// <summary>
/// Username. /// Username.
/// </summary> /// </summary>
public string UserName { public string UserName {
get { return UseDefaultCredentials ? DefaultCredentials.Value.UserName : userName; } get { return UseDefaultCredentials ? defaultCredentials.Value.UserName : userName; }
set set
{ {
userName = value; userName = value;
if (DefaultCredentials.Value.UserName != userName) if (defaultCredentials.Value.UserName != userName)
{ {
UseDefaultCredentials = false; UseDefaultCredentials = false;
} }
...@@ -39,12 +44,12 @@ namespace Titanium.Web.Proxy.Models ...@@ -39,12 +44,12 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public string Password public string Password
{ {
get { return UseDefaultCredentials ? DefaultCredentials.Value.Password : password; } get { return UseDefaultCredentials ? defaultCredentials.Value.Password : password; }
set set
{ {
password = value; password = value;
if (DefaultCredentials.Value.Password != password) if (defaultCredentials.Value.Password != password)
{ {
UseDefaultCredentials = false; UseDefaultCredentials = false;
} }
......
...@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary> /// <summary>
/// Implements certificate generation operations. /// Implements certificate generation operations.
/// </summary> /// </summary>
public class BCCertificateMaker : ICertificateMaker internal class BCCertificateMaker : ICertificateMaker
{ {
private const int CertificateValidDays = 1825; private const int certificateValidDays = 1825;
private const int CertificateGraceDays = 366; private const int certificateGraceDays = 366;
/// <summary> /// <summary>
/// Makes the certificate. /// Makes the certificate.
...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return certificate; return certificate;
} }
return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-CertificateGraceDays), DateTime.UtcNow.AddDays(CertificateValidDays), isRoot ? null : signingCert); return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert);
} }
} }
......
...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// Certificate Maker - uses MakeCert /// Certificate Maker - uses MakeCert
/// Calls COM objects using reflection /// Calls COM objects using reflection
/// </summary> /// </summary>
public class WinCertificateMaker : ICertificateMaker internal class WinCertificateMaker : ICertificateMaker
{ {
private readonly Type typeX500DN; private readonly Type typeX500DN;
...@@ -42,12 +42,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -42,12 +42,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"; private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
private object _SharedPrivateKey; private object sharedPrivateKey;
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
public WinCertificateMaker() internal WinCertificateMaker()
{ {
typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true); typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true);
typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true); typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true);
...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
sharedPrivateKey = _SharedPrivateKey; sharedPrivateKey = this.sharedPrivateKey;
} }
if (sharedPrivateKey == null) if (sharedPrivateKey == null)
...@@ -130,52 +130,52 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -130,52 +130,52 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
_SharedPrivateKey = sharedPrivateKey; this.sharedPrivateKey = sharedPrivateKey;
} }
} }
typeValue = new object[1]; typeValue = new object[1];
var OID = Activator.CreateInstance(typeOID); var oid = Activator.CreateInstance(typeOID);
typeValue[0] = "1.3.6.1.5.5.7.3.1"; typeValue[0] = "1.3.6.1.5.5.7.3.1";
typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, OID, typeValue); typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, oid, typeValue);
var OIDS = Activator.CreateInstance(typeOIDS); var oids = Activator.CreateInstance(typeOIDS);
typeValue[0] = OID; typeValue[0] = oid;
typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, OIDS, typeValue); typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, oids, typeValue);
var EKUExt = Activator.CreateInstance(typeEKUExt); var ekuExt = Activator.CreateInstance(typeEKUExt);
typeValue[0] = OIDS; typeValue[0] = oids;
typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, EKUExt, typeValue); typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, ekuExt, typeValue);
var RequestCert = Activator.CreateInstance(typeRequestCert); var requestCert = Activator.CreateInstance(typeRequestCert);
typeValue = new[] { 1, sharedPrivateKey, string.Empty }; typeValue = new[] { 1, sharedPrivateKey, string.Empty };
typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, RequestCert, typeValue); typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, requestCert, typeValue);
typeValue = new[] { x500CertDN }; typeValue = new[] { x500CertDN };
typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = x500RootCertDN; typeValue[0] = x500RootCertDN;
typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = validFrom; typeValue[0] = validFrom;
typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = validTo; typeValue[0] = validTo;
typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, requestCert, typeValue);
var KUExt = Activator.CreateInstance(typeKUExt); var kuExt = Activator.CreateInstance(typeKUExt);
typeValue[0] = 176; typeValue[0] = 176;
typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, KUExt, typeValue); typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, kuExt, typeValue);
var certificate = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, RequestCert, null); var certificate = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, requestCert, null);
typeValue = new object[1]; typeValue = new object[1];
if (!isRoot) if (!isRoot)
{ {
typeValue[0] = KUExt; typeValue[0] = kuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
typeValue[0] = EKUExt; typeValue[0] = ekuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
if (!isRoot) if (!isRoot)
...@@ -203,12 +203,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -203,12 +203,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
var SignerCertificate = Activator.CreateInstance(typeSignerCertificate); var signerCertificate = Activator.CreateInstance(typeSignerCertificate);
typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint }; typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint };
typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, SignerCertificate, typeValue); typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, signerCertificate, typeValue);
typeValue = new[] { SignerCertificate }; typeValue = new[] { signerCertificate };
typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, requestCert, typeValue);
} }
else else
{ {
...@@ -220,24 +220,24 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -220,24 +220,24 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
OID = Activator.CreateInstance(typeOID); oid = Activator.CreateInstance(typeOID);
typeValue = new object[] { 1, 0, 0, hashAlg }; typeValue = new object[] { 1, 0, 0, hashAlg };
typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, OID, typeValue); typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, oid, typeValue);
typeValue = new[] { OID }; typeValue = new[] { oid };
typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, RequestCert, null); typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, requestCert, null);
var X509Enrollment = Activator.CreateInstance(typeX509Enrollment); var x509Enrollment = Activator.CreateInstance(typeX509Enrollment);
typeValue[0] = RequestCert; typeValue[0] = requestCert;
typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
if (isRoot) if (isRoot)
{ {
typeValue[0] = fullSubject; typeValue[0] = fullSubject;
typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, x509Enrollment, typeValue);
} }
...@@ -245,15 +245,15 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -245,15 +245,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue[0] = 0; typeValue[0] = 0;
var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new[] { 2, createCertRequest, 0, string.Empty }; typeValue = new[] { 2, createCertRequest, 0, string.Empty };
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new object[] { null, 0, 1 }; typeValue = new object[] { null, 0, 1 };
try try
{ {
var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable); return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
} }
catch (Exception) catch (Exception)
......
...@@ -31,6 +31,10 @@ namespace Titanium.Web.Proxy.Network ...@@ -31,6 +31,10 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal class CertificateManager : IDisposable internal class CertificateManager : IDisposable
{ {
private const string defaultRootCertificateIssuer = "Titanium";
private const string defaultRootRootCertificateName = "Titanium Root Certificate Authority";
private readonly ICertificateMaker certEngine; private readonly ICertificateMaker certEngine;
private bool clearCertificates { get; set; } private bool clearCertificates { get; set; }
...@@ -66,8 +70,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -66,8 +70,8 @@ namespace Titanium.Web.Proxy.Network
certEngine = new WinCertificateMaker(); certEngine = new WinCertificateMaker();
} }
Issuer = issuer; Issuer = issuer ?? defaultRootCertificateIssuer;
RootCertificateName = rootCertificateName; RootCertificateName = rootCertificateName ?? defaultRootRootCertificateName;
certificateCache = new ConcurrentDictionary<string, CachedCertificate>(); certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
} }
...@@ -88,7 +92,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -88,7 +92,7 @@ namespace Titanium.Web.Proxy.Network
return fileName; return fileName;
} }
internal X509Certificate2 GetRootCertificate() internal X509Certificate2 LoadRootCertificate()
{ {
var fileName = GetRootCertificatePath(); var fileName = GetRootCertificatePath();
if (!File.Exists(fileName)) return null; if (!File.Exists(fileName)) return null;
...@@ -108,11 +112,16 @@ namespace Titanium.Web.Proxy.Network ...@@ -108,11 +112,16 @@ namespace Titanium.Web.Proxy.Network
/// <returns>true if succeeded, else false</returns> /// <returns>true if succeeded, else false</returns>
internal bool CreateTrustedRootCertificate() internal bool CreateTrustedRootCertificate()
{ {
RootCertificate = GetRootCertificate(); if (RootCertificate == null)
{
RootCertificate = LoadRootCertificate();
}
if (RootCertificate != null) if (RootCertificate != null)
{ {
return true; return true;
} }
try try
{ {
RootCertificate = CreateCertificate(RootCertificateName, true); RootCertificate = CreateCertificate(RootCertificateName, true);
...@@ -121,6 +130,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -121,6 +130,7 @@ namespace Titanium.Web.Proxy.Network
{ {
exceptionFunc(e); exceptionFunc(e);
} }
if (RootCertificate != null) if (RootCertificate != null)
{ {
try try
...@@ -133,9 +143,23 @@ namespace Titanium.Web.Proxy.Network ...@@ -133,9 +143,23 @@ namespace Titanium.Web.Proxy.Network
exceptionFunc(e); exceptionFunc(e);
} }
} }
return RootCertificate != null; return RootCertificate != null;
} }
/// <summary>
/// Trusts the root certificate.
/// </summary>
/// <param name="exceptionFunc"></param>
internal void TrustRootCertificate(Action<Exception> exceptionFunc)
{
//current user
TrustRootCertificate(StoreLocation.CurrentUser, exceptionFunc);
//current system
TrustRootCertificate(StoreLocation.LocalMachine, exceptionFunc);
}
/// <summary> /// <summary>
/// Create an SSL certificate /// Create an SSL certificate
/// </summary> /// </summary>
...@@ -144,15 +168,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -144,15 +168,13 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns> /// <returns></returns>
internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate) internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
{ {
if (certificateCache.ContainsKey(certificateName)) if (certificateCache.ContainsKey(certificateName))
{ {
var cached = certificateCache[certificateName]; var cached = certificateCache[certificateName];
cached.LastAccess = DateTime.Now; cached.LastAccess = DateTime.Now;
return cached.Certificate; return cached.Certificate;
} }
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
lock (string.Intern(certificateName)) lock (string.Intern(certificateName))
{ {
...@@ -160,6 +182,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -160,6 +182,11 @@ namespace Titanium.Web.Proxy.Network
{ {
try try
{ {
if (!isRootCertificate && RootCertificate == null)
{
CreateTrustedRootCertificate();
}
certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate); certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
} }
catch (Exception e) catch (Exception e)
...@@ -168,7 +195,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -168,7 +195,7 @@ namespace Titanium.Web.Proxy.Network
} }
if (certificate != null && !certificateCache.ContainsKey(certificateName)) if (certificate != null && !certificateCache.ContainsKey(certificateName))
{ {
certificateCache.Add(certificateName, new CachedCertificate() { Certificate = certificate }); certificateCache.Add(certificateName, new CachedCertificate { Certificate = certificate });
} }
} }
else else
...@@ -182,10 +209,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -182,10 +209,7 @@ namespace Titanium.Web.Proxy.Network
} }
} }
return certificate; return certificate;
} }
/// <summary> /// <summary>
......
...@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// This class wraps Tcp connection to client /// This class wraps Tcp connection to client
/// </summary> /// </summary>
public class ProxyClient internal class ProxyClient
{ {
/// <summary> /// <summary>
/// TcpClient used to communicate with client /// TcpClient used to communicate with client
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// An object that holds TcpConnection to a particular server and port /// An object that holds TcpConnection to a particular server and port
/// </summary> /// </summary>
public class TcpConnection : IDisposable internal class TcpConnection : IDisposable
{ {
internal ExternalProxy UpStreamHttpProxy { get; set; } internal ExternalProxy UpStreamHttpProxy { get; set; }
......
...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpRow"/> class. /// Initializes a new instance of the <see cref="TcpRow"/> class.
/// </summary> /// </summary>
/// <param name="tcpRow">TcpRow struct.</param> /// <param name="tcpRow">TcpRow struct.</param>
public TcpRow(NativeMethods.TcpRow tcpRow) internal TcpRow(NativeMethods.TcpRow tcpRow)
{ {
ProcessId = tcpRow.owningPid; ProcessId = tcpRow.owningPid;
...@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Gets the local end point. /// Gets the local end point.
/// </summary> /// </summary>
public IPEndPoint LocalEndPoint { get; } internal IPEndPoint LocalEndPoint { get; }
/// <summary> /// <summary>
/// Gets the remote end point. /// Gets the remote end point.
/// </summary> /// </summary>
public IPEndPoint RemoteEndPoint { get; } internal IPEndPoint RemoteEndPoint { get; }
/// <summary> /// <summary>
/// Gets the process identifier. /// Gets the process identifier.
/// </summary> /// </summary>
public int ProcessId { get; } internal int ProcessId { get; }
} }
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpTable"/> class. /// Initializes a new instance of the <see cref="TcpTable"/> class.
/// </summary> /// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param> /// <param name="tcpRows">TcpRow collection to initialize with.</param>
public TcpTable(IEnumerable<TcpRow> tcpRows) internal TcpTable(IEnumerable<TcpRow> tcpRows)
{ {
this.tcpRows = tcpRows; this.tcpRows = tcpRows;
} }
...@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Gets the TCP rows. /// Gets the TCP rows.
/// </summary> /// </summary>
public IEnumerable<TcpRow> TcpRows => tcpRows; internal IEnumerable<TcpRow> TcpRows => tcpRows;
/// <summary> /// <summary>
/// Returns an enumerator that iterates through the collection. /// Returns an enumerator that iterates through the collection.
......
This diff is collapsed.
...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy ...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy
sslStream = new SslStream(clientStream, true); sslStream = new SslStream(clientStream, true);
var certificate = endPoint.GenericCertificate ?? certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); var certificate = endPoint.GenericCertificate ?? certificateManager.CreateCertificate(httpRemoteUri.Host, false);
//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, await sslStream.AuthenticateAsServerAsync(certificate, false,
...@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy ...@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response //write back successfull CONNECT response
await WriteConnectResponse(clientStreamWriter, version); await WriteConnectResponse(clientStreamWriter, version);
await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(BufferSize, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
null, version, null, null, version, null,
false, SupportedSslProtocols, false, SupportedSslProtocols,
ValidateServerCertificate, ValidateServerCertificate,
...@@ -185,7 +185,7 @@ namespace Titanium.Web.Proxy ...@@ -185,7 +185,7 @@ namespace Titanium.Web.Proxy
var sslStream = new SslStream(clientStream, true); var sslStream = new SslStream(clientStream, true);
//implement in future once SNI supported by SSL stream, for now use the same certificate //implement in future once SNI supported by SSL stream, for now use the same certificate
var certificate = certificateCacheManager.CreateCertificate(endPoint.GenericCertificateName, false); var certificate = certificateManager.CreateCertificate(endPoint.GenericCertificateName, false);
try try
{ {
...@@ -245,7 +245,7 @@ namespace Titanium.Web.Proxy ...@@ -245,7 +245,7 @@ namespace Titanium.Web.Proxy
args.CustomUpStreamHttpProxyUsed = customUpStreamHttpProxy; args.CustomUpStreamHttpProxyUsed = customUpStreamHttpProxy;
args.CustomUpStreamHttpsProxyUsed = customUpStreamHttpsProxy; args.CustomUpStreamHttpsProxyUsed = customUpStreamHttpsProxy;
connection = await tcpConnectionFactory.CreateClient(BUFFER_SIZE, ConnectionTimeOutSeconds, connection = await tcpConnectionFactory.CreateClient(BufferSize, ConnectionTimeOutSeconds,
args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.WebSession.Request.HttpVersion, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.WebSession.Request.HttpVersion,
args.IsHttps, SupportedSslProtocols, args.IsHttps, SupportedSslProtocols,
ValidateServerCertificate, ValidateServerCertificate,
...@@ -378,7 +378,7 @@ namespace Titanium.Web.Proxy ...@@ -378,7 +378,7 @@ namespace Titanium.Web.Proxy
} }
var args = var args =
new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse) new SessionEventArgs(BufferSize, HandleHttpSessionResponse)
{ {
ProxyClient = {TcpClient = client}, ProxyClient = {TcpClient = client},
WebSession = {ConnectHeaders = connectHeaders} WebSession = {ConnectHeaders = connectHeaders}
...@@ -487,7 +487,7 @@ namespace Titanium.Web.Proxy ...@@ -487,7 +487,7 @@ namespace Titanium.Web.Proxy
//if upgrading to websocket then relay the requet without reading the contents //if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket) if (args.WebSession.Request.UpgradeToWebSocket)
{ {
await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(BufferSize, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps,
SupportedSslProtocols, ValidateServerCertificate, SupportedSslProtocols, ValidateServerCertificate,
SelectClientCertificate, SelectClientCertificate,
...@@ -581,14 +581,14 @@ namespace Titanium.Web.Proxy ...@@ -581,14 +581,14 @@ namespace Titanium.Web.Proxy
//send the request body bytes to server //send the request body bytes to server
if (args.WebSession.Request.ContentLength > 0) if (args.WebSession.Request.ContentLength > 0)
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(BUFFER_SIZE, postStream, args.WebSession.Request.ContentLength); await args.ProxyClient.ClientStreamReader.CopyBytesToStream(BufferSize, postStream, args.WebSession.Request.ContentLength);
} }
//Need to revist, find any potential bugs //Need to revist, find any potential bugs
//send the request body bytes to server in chunks //send the request body bytes to server in chunks
else if (args.WebSession.Request.IsChunked) else if (args.WebSession.Request.IsChunked)
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(BUFFER_SIZE, postStream); await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(BufferSize, postStream);
} }
} }
} }
......
...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy ...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
/// <returns></returns> /// <returns></returns>
public async Task HandleHttpSessionResponse(SessionEventArgs args) private async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
//read response & headers from server //read response & headers from server
await args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse();
...@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy ...@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy
|| !args.WebSession.Response.ResponseKeepAlive) || !args.WebSession.Response.ResponseKeepAlive)
{ {
await args.WebSession.ServerConnection.StreamReader await args.WebSession.ServerConnection.StreamReader
.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, .WriteResponseBody(BufferSize, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked,
args.WebSession.Response.ContentLength); args.WebSession.Response.ContentLength);
} }
//write response if connection:keep-alive header exist and when version is http/1.0 //write response if connection:keep-alive header exist and when version is http/1.0
...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy ...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy
else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0) else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0)
{ {
await args.WebSession.ServerConnection.StreamReader await args.WebSession.ServerConnection.StreamReader
.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, .WriteResponseBody(BufferSize, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked,
args.WebSession.Response.ContentLength); args.WebSession.Response.ContentLength);
} }
} }
......
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