Commit e4dfa442 authored by titanium007's avatar titanium007

issue #13 Fix

Mark items internal; keep only MRU certificates in cache
parent dfc6d9a6
namespace Titanium.Web.Proxy.Decompression
{
class DecompressionFactory
internal class DecompressionFactory
{
public IDecompression Create(string type)
internal IDecompression Create(string type)
{
switch(type)
{
......
......@@ -2,7 +2,7 @@
namespace Titanium.Web.Proxy.Decompression
{
class DefaultDecompression : IDecompression
internal class DefaultDecompression : IDecompression
{
public Task<byte[]> Decompress(byte[] compressedArray)
{
......
......@@ -5,7 +5,7 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression
{
class DeflateDecompression : IDecompression
internal class DeflateDecompression : IDecompression
{
public async Task<byte[]> Decompress(byte[] compressedArray)
{
......
......@@ -5,7 +5,7 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression
{
class GZipDecompression : IDecompression
internal class GZipDecompression : IDecompression
{
public async Task<byte[]> Decompress(byte[] compressedArray)
{
......
......@@ -3,7 +3,7 @@ using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression
{
interface IDecompression
internal interface IDecompression
{
Task<byte[]> Decompress(byte[] compressedArray);
}
......
......@@ -5,7 +5,7 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression
{
class ZlibDecompression : IDecompression
internal class ZlibDecompression : IDecompression
{
public async Task<byte[]> Decompress(byte[] compressedArray)
{
......
......@@ -7,10 +7,10 @@ namespace Titanium.Web.Proxy.Extensions
/// <summary>
/// Extensions on HttpWebSession object
/// </summary>
public static class HttpWebRequestExtensions
internal static class HttpWebRequestExtensions
{
//Get encoding of the HTTP request
public static Encoding GetEncoding(this Request request)
internal static Encoding GetEncoding(this Request request)
{
try
{
......
......@@ -4,9 +4,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebResponseExtensions
internal static class HttpWebResponseExtensions
{
public static Encoding GetResponseCharacterEncoding(this Response response)
internal static Encoding GetResponseCharacterEncoding(this Response response)
{
try
{
......
......@@ -8,9 +8,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Extensions
{
public static class StreamHelper
internal static class StreamHelper
{
public static async Task CopyToAsync(this Stream input, string initialData, Stream output)
internal static async Task CopyToAsync(this Stream input, string initialData, Stream output)
{
if (!string.IsNullOrEmpty(initialData))
{
......
using System.Net.Sockets;
namespace Titanium.Web.Proxy.Extensions
{
internal static class TcpExtensions
{
public static bool IsConnected(this Socket client)
internal static bool IsConnected(this Socket client)
{
// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
......
......@@ -6,24 +6,37 @@ using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using System.Threading.Tasks;
using System.Threading;
using System.Linq;
namespace Titanium.Web.Proxy.Helpers
{
public class CertificateManager : IDisposable
internal class CachedCertificate
{
internal X509Certificate2 Certificate { get; set; }
internal DateTime LastAccess { get; set; }
internal CachedCertificate()
{
LastAccess = DateTime.Now;
}
}
internal class CertificateManager : IDisposable
{
private const string CertCreateFormat =
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 {5}";
private readonly IDictionary<string, X509Certificate2> _certificateCache;
private readonly IDictionary<string, CachedCertificate> certificateCache;
private static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1);
public string Issuer { get; private set; }
public string RootCertificateName { get; private set; }
internal string Issuer { get; private set; }
internal string RootCertificateName { get; private set; }
public X509Store MyStore { get; private set; }
public X509Store RootStore { get; private set; }
internal X509Store MyStore { get; private set; }
internal X509Store RootStore { get; private set; }
public CertificateManager(string issuer, string rootCertificateName)
internal CertificateManager(string issuer, string rootCertificateName)
{
Issuer = issuer;
RootCertificateName = rootCertificateName;
......@@ -31,17 +44,17 @@ namespace Titanium.Web.Proxy.Helpers
MyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
RootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
_certificateCache = new Dictionary<string, X509Certificate2>();
certificateCache = new Dictionary<string, CachedCertificate>();
}
/// <summary>
/// Attempts to move a self-signed certificate to the root store.
/// </summary>
/// <returns>true if succeeded, else false</returns>
public async Task<bool> CreateTrustedRootCertificate()
internal async Task<bool> CreateTrustedRootCertificate()
{
X509Certificate2 rootCertificate =
await CreateCertificate(RootStore, RootCertificateName);
await CreateCertificate(RootStore, RootCertificateName, true);
return rootCertificate != null;
}
......@@ -49,12 +62,12 @@ namespace Titanium.Web.Proxy.Helpers
/// Attempts to remove the self-signed certificate from the root store.
/// </summary>
/// <returns>true if succeeded, else false</returns>
public async Task<bool> DestroyTrustedRootCertificate()
internal bool DestroyTrustedRootCertificate()
{
return await DestroyCertificate(RootStore, RootCertificateName);
return DestroyCertificate(RootStore, RootCertificateName, false);
}
public X509Certificate2Collection FindCertificates(string certificateSubject)
internal X509Certificate2Collection FindCertificates(string certificateSubject)
{
return FindCertificates(MyStore, certificateSubject);
}
......@@ -67,29 +80,36 @@ namespace Titanium.Web.Proxy.Helpers
discoveredCertificates : null;
}
public async Task<X509Certificate2> CreateCertificate(string certificateName)
internal async Task<X509Certificate2> CreateCertificate(string certificateName, bool isRootCertificate)
{
return await CreateCertificate(MyStore, certificateName);
return await CreateCertificate(MyStore, certificateName, isRootCertificate);
}
protected async virtual Task<X509Certificate2> CreateCertificate(X509Store store, string certificateName)
{
if (_certificateCache.ContainsKey(certificateName))
return _certificateCache[certificateName];
protected async virtual Task<X509Certificate2> CreateCertificate(X509Store store, string certificateName, bool isRootCertificate)
{
await semaphoreLock.WaitAsync();
X509Certificate2 certificate = null;
try
{
if (certificateCache.ContainsKey(certificateName))
{
var cached = certificateCache[certificateName];
cached.LastAccess = DateTime.Now;
return cached.Certificate;
}
X509Certificate2 certificate = null;
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
var certificates =
FindCertificates(store, certificateSubject);
X509Certificate2Collection certificates;
if (isRootCertificate)
{
certificates = FindCertificates(store, certificateSubject);
if (certificates != null)
certificate = certificates[0];
}
if (certificate == null)
{
......@@ -99,13 +119,17 @@ namespace Titanium.Web.Proxy.Helpers
await CreateCertificate(args);
certificates = FindCertificates(store, certificateSubject);
return certificates != null ?
certificates[0] : null;
//remove it from store
if (!isRootCertificate)
DestroyCertificate(certificateName);
if (certificates != null)
certificate = certificates[0];
}
store.Close();
if (certificate != null && !_certificateCache.ContainsKey(certificateName))
_certificateCache.Add(certificateName, certificate);
if (certificate != null && !certificateCache.ContainsKey(certificateName))
certificateCache.Add(certificateName, new CachedCertificate() { Certificate = certificate });
return certificate;
}
......@@ -113,8 +137,8 @@ namespace Titanium.Web.Proxy.Helpers
{
semaphoreLock.Release();
}
}
protected virtual Task<int> CreateCertificate(string[] args)
{
......@@ -153,17 +177,15 @@ namespace Titanium.Web.Proxy.Helpers
}
public async Task<bool> DestroyCertificate(string certificateName)
internal bool DestroyCertificate(string certificateName)
{
return await DestroyCertificate(MyStore, certificateName);
return DestroyCertificate(MyStore, certificateName, false);
}
protected virtual async Task<bool> DestroyCertificate(X509Store store, string certificateName)
{
await semaphoreLock.WaitAsync();
X509Certificate2Collection certificates = null;
try
protected virtual bool DestroyCertificate(X509Store store, string certificateName, bool removeFromCache)
{
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
......@@ -175,19 +197,13 @@ namespace Titanium.Web.Proxy.Helpers
}
store.Close();
if (certificates == null &&
_certificateCache.ContainsKey(certificateName))
if (removeFromCache &&
certificateCache.ContainsKey(certificateName))
{
_certificateCache.Remove(certificateName);
certificateCache.Remove(certificateName);
}
return certificates == null;
}
finally
{
semaphoreLock.Release();
}
}
protected virtual string GetCertificateCreateArgs(X509Store store, string certificateName)
{
......@@ -203,6 +219,37 @@ namespace Titanium.Web.Proxy.Helpers
return certCreatArgs;
}
private static bool clearCertificates { get; set; }
internal void StopClearIdleCertificates()
{
clearCertificates = false;
}
internal async void ClearIdleCertificates()
{
clearCertificates = true;
while (clearCertificates)
{
await semaphoreLock.WaitAsync();
try
{
var cutOff = DateTime.Now.AddSeconds(-60);
var outdated = certificateCache
.Where(x => x.Value.LastAccess < cutOff)
.ToList();
foreach (var cache in outdated)
certificateCache.Remove(cache.Key);
}
finally { semaphoreLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
}
}
public void Dispose()
{
if (MyStore != null)
......
......@@ -15,18 +15,16 @@ namespace Titanium.Web.Proxy.Helpers
/// using the specified encoding
/// as well as to read bytes as required
/// </summary>
public class CustomBinaryReader : IDisposable
internal class CustomBinaryReader : IDisposable
{
private Stream stream;
internal CustomBinaryReader(Stream stream)
{
this.stream = stream;
}
public Stream BaseStream => stream;
internal Stream BaseStream => stream;
/// <summary>
/// Read a line from the byte stream
......@@ -41,25 +39,25 @@ namespace Titanium.Web.Proxy.Helpers
var lastChar = default(char);
var buffer = new byte[1];
while (await this.stream.ReadAsync(buffer, 0, 1).ConfigureAwait(false) > 0)
while (this.stream.Read(buffer, 0, 1) > 0)
{
if (lastChar == '\r' && buffer[0] == '\n')
{
return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
return await Task.FromResult(readBuffer.Remove(readBuffer.Length - 1, 1).ToString());
}
if (buffer[0] == '\0')
{
return readBuffer.ToString();
return await Task.FromResult(readBuffer.ToString());
}
readBuffer.Append((char)buffer[0]);
lastChar = (char)buffer[0];
}
return readBuffer.ToString();
return await Task.FromResult(readBuffer.ToString());
}
catch (IOException)
{
return readBuffer.ToString();
return await Task.FromResult(readBuffer.ToString());
}
}
......
......@@ -16,9 +16,9 @@ namespace Titanium.Web.Proxy.Helpers
internal class HttpSystemProxyValue
{
public string HostName { get; set; }
public int Port { get; set; }
public bool IsHttps { get; set; }
internal string HostName { get; set; }
internal int Port { get; set; }
internal bool IsHttps { get; set; }
public override string ToString()
{
......@@ -29,12 +29,12 @@ namespace Titanium.Web.Proxy.Helpers
}
}
public static class SystemProxyHelper
internal static class SystemProxyHelper
{
public const int InternetOptionSettingsChanged = 39;
public const int InternetOptionRefresh = 37;
internal const int InternetOptionSettingsChanged = 39;
internal const int InternetOptionRefresh = 37;
public static void SetHttpProxy(string hostname, int port)
internal static void SetHttpProxy(string hostname, int port)
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
......@@ -60,7 +60,7 @@ namespace Titanium.Web.Proxy.Helpers
}
public static void RemoveHttpProxy()
internal static void RemoveHttpProxy()
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
......@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Helpers
Refresh();
}
public static void SetHttpsProxy(string hostname, int port)
internal static void SetHttpsProxy(string hostname, int port)
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
......@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy.Helpers
Refresh();
}
public static void RemoveHttpsProxy()
internal static void RemoveHttpsProxy()
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
......@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.Helpers
Refresh();
}
public static void DisableAllProxy()
internal static void DisableAllProxy()
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
......
......@@ -12,9 +12,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers
{
public class TcpHelper
internal class TcpHelper
{
public async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
internal async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
int tunnelPort, bool isHttps)
{
StringBuilder sb = null;
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal SessionEventArgs Session { get; set; }
public CustomSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
internal CustomSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
:base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback)
{
......
......@@ -28,7 +28,6 @@ namespace Titanium.Web.Proxy.Network
internal DateTime LastAccess { get; set; }
internal TcpConnection()
{
LastAccess = DateTime.Now;
......@@ -192,9 +191,17 @@ namespace Titanium.Web.Proxy.Network
finally { connectionAccessLock.Release(); }
}
private static bool clearConenctions { get; set; }
internal static void StopClearIdleConnections()
{
clearConenctions = false;
}
internal async static void ClearIdleConnections()
{
while (true)
clearConenctions = true;
while (clearConenctions)
{
await connectionAccessLock.WaitAsync();
try
......
......@@ -22,7 +22,6 @@ namespace Titanium.Web.Proxy
static ProxyServer()
{
ProxyEndPoints = new List<ProxyEndPoint>();
Initialize();
}
private static CertificateManager CertManager { get; set; }
......@@ -58,6 +57,13 @@ namespace Titanium.Web.Proxy
public static void Initialize()
{
TcpConnectionManager.ClearIdleConnections();
CertManager.ClearIdleCertificates();
}
public static void Quit()
{
TcpConnectionManager.StopClearIdleConnections();
CertManager.StopClearIdleCertificates();
}
public static void AddEndPoint(ProxyEndPoint endPoint)
......@@ -161,6 +167,8 @@ namespace Titanium.Web.Proxy
Listen(endPoint);
}
Initialize();
proxyRunning = true;
}
......@@ -186,6 +194,8 @@ namespace Titanium.Web.Proxy
CertManager.Dispose();
Quit();
proxyRunning = false;
}
......
......@@ -74,7 +74,7 @@ namespace Titanium.Web.Proxy
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
SslStream sslStream = null;
......@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy
// certificate = CertManager.CreateCertificate(hostName);
//}
//else
certificate = await CertManager.CreateCertificate(endPoint.GenericCertificateName);
certificate = await CertManager.CreateCertificate(endPoint.GenericCertificateName, false);
try
{
......
......@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Shared
/// </summary>
internal class Constants
{
public static readonly int BUFFER_SIZE = 8192;
internal static readonly int BUFFER_SIZE = 8192;
internal static readonly char[] SpaceSplit = { ' ' };
internal static readonly char[] ColonSplit = { ':' };
......
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