Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
31edf6dd
Commit
31edf6dd
authored
Apr 07, 2017
by
Rob Garrett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resharper cleanup
parent
2b3f9ffe
Show whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
622 additions
and
493 deletions
+622
-493
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+14
-12
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+0
-1
CertificateSelectionEventArgs.cs
...Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
+18
-1
CertificateValidationEventArgs.cs
...eb.Proxy/EventArguments/CertificateValidationEventArgs.cs
+13
-6
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+21
-6
BodyNotFoundException.cs
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
+5
-2
ByteArrayExtensions.cs
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
+4
-1
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+3
-10
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+6
-6
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+28
-28
Network.cs
Titanium.Web.Proxy/Helpers/Network.cs
+6
-24
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+1
-4
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+1
-0
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+42
-36
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+10
-22
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+14
-9
GenericResponse.cs
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
+10
-1
OkResponse.cs
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
+3
-0
RedirectResponse.cs
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
+3
-0
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+47
-11
ExternalProxy.cs
Titanium.Web.Proxy/Models/ExternalProxy.cs
+17
-2
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+13
-1
CertificateMaker.cs
Titanium.Web.Proxy/Network/CertificateMaker.cs
+115
-118
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+38
-48
TcpConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
+3
-0
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+2
-4
TcpRow.cs
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
+3
-3
TcpTable.cs
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
+3
-1
ProxyAuthorizationHandler.cs
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
+64
-40
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+61
-14
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+41
-63
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+12
-17
ProxyConstants.cs
Titanium.Web.Proxy/Shared/ProxyConstants.cs
+1
-2
No files found.
Titanium.Web.Proxy/CertificateHandler.cs
View file @
31edf6dd
using
System
;
using
System.Linq
;
using
System.Net.Security
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading.Tasks
;
...
...
@@ -26,11 +25,13 @@ namespace Titanium.Web.Proxy
//if user callback is registered then do it
if
(
ServerCertificateValidationCallback
!=
null
)
{
var
args
=
new
CertificateValidationEventArgs
();
var
args
=
new
CertificateValidationEventArgs
{
Certificate
=
certificate
,
Chain
=
chain
,
SslPolicyErrors
=
sslPolicyErrors
};
args
.
Certificate
=
certificate
;
args
.
Chain
=
chain
;
args
.
SslPolicyErrors
=
sslPolicyErrors
;
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
...
...
@@ -73,7 +74,6 @@ namespace Titanium.Web.Proxy
string
[]
acceptableIssuers
)
{
X509Certificate
clientCertificate
=
null
;
var
customSslStream
=
sender
as
SslStream
;
if
(
acceptableIssuers
!=
null
&&
acceptableIssuers
.
Length
>
0
&&
...
...
@@ -100,13 +100,15 @@ namespace Titanium.Web.Proxy
//If user call back is registered
if
(
ClientCertificateSelectionCallback
!=
null
)
{
var
args
=
new
CertificateSelectionEventArgs
();
var
args
=
new
CertificateSelectionEventArgs
{
TargetHost
=
targetHost
,
LocalCertificates
=
localCertificates
,
RemoteCertificate
=
remoteCertificate
,
AcceptableIssuers
=
acceptableIssuers
,
ClientCertificate
=
clientCertificate
};
args
.
TargetHost
=
targetHost
;
args
.
LocalCertificates
=
localCertificates
;
args
.
RemoteCertificate
=
remoteCertificate
;
args
.
AcceptableIssuers
=
acceptableIssuers
;
args
.
ClientCertificate
=
clientCertificate
;
Delegate
[]
invocationList
=
ClientCertificateSelectionCallback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
31edf6dd
using
System.IO
;
using
System.IO.Compression
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Decompression
{
...
...
Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
View file @
31edf6dd
...
...
@@ -8,12 +8,29 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
class
CertificateSelectionEventArgs
:
EventArgs
{
/// <summary>
/// Sender object.
/// </summary>
public
object
Sender
{
get
;
internal
set
;
}
/// <summary>
/// Target host.
/// </summary>
public
string
TargetHost
{
get
;
internal
set
;
}
/// <summary>
/// Local certificates.
/// </summary>
public
X509CertificateCollection
LocalCertificates
{
get
;
internal
set
;
}
/// <summary>
/// Remote certificate.
/// </summary>
public
X509Certificate
RemoteCertificate
{
get
;
internal
set
;
}
/// <summary>
/// Acceptable issuers.
/// </summary>
public
string
[]
AcceptableIssuers
{
get
;
internal
set
;
}
/// <summary>
/// Client Certificate.
/// </summary>
public
X509Certificate
ClientCertificate
{
get
;
set
;
}
}
...
...
Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs
View file @
31edf6dd
...
...
@@ -7,17 +7,24 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// An argument passed on to the user for validating the server certificate during SSL authentication
/// </summary>
public
class
CertificateValidationEventArgs
:
EventArgs
,
IDisposable
public
class
CertificateValidationEventArgs
:
EventArgs
{
/// <summary>
/// Certificate
/// </summary>
public
X509Certificate
Certificate
{
get
;
internal
set
;
}
/// <summary>
/// Certificate chain
/// </summary>
public
X509Chain
Chain
{
get
;
internal
set
;
}
/// <summary>
/// SSL policy errors.
/// </summary>
public
SslPolicyErrors
SslPolicyErrors
{
get
;
internal
set
;
}
/// <summary>
/// is a valid certificate?
/// </summary>
public
bool
IsValid
{
get
;
set
;
}
public
void
Dispose
()
{
}
}
}
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
31edf6dd
...
...
@@ -44,7 +44,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
Guid
Id
=>
WebSession
.
RequestId
;
//Should we send a rerequest
/// <summary>
/// Should we send a rerequest
/// </summary>
public
bool
ReRequest
{
get
;
...
...
@@ -56,7 +58,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
bool
IsHttps
=>
WebSession
.
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
/// <summary>
/// Client End Point.
/// </summary>
public
IPEndPoint
ClientEndPoint
=>
(
IPEndPoint
)
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
/// <summary>
...
...
@@ -65,8 +69,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
HttpWebClient
WebSession
{
get
;
set
;
}
/// <summary>
/// Are we using a custom upstream HTTP proxy?
/// </summary>
public
ExternalProxy
CustomUpStreamHttpProxyUsed
{
get
;
set
;
}
/// <summary>
/// Are we using a custom upstream HTTPS proxy?
/// </summary>
public
ExternalProxy
CustomUpStreamHttpsProxyUsed
{
get
;
set
;
}
/// <summary>
...
...
@@ -105,7 +115,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
WebSession
.
Request
.
IsChunked
)
{
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
}
else
{
...
...
@@ -113,7 +123,7 @@ namespace Titanium.Web.Proxy.EventArguments
if
(
WebSession
.
Request
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
}
...
...
@@ -431,7 +441,7 @@ namespace Titanium.Web.Proxy.EventArguments
await
GenericResponse
(
html
,
null
,
status
);
}
///
<summary>
///
<summary>
/// Before request is made to server
/// Respond with the specified HTML string to client
/// and the specified status
...
...
@@ -485,12 +495,17 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Request
.
CancelRequest
=
true
;
}
/// <summary>
/// Redirect to URL.
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public
async
Task
Redirect
(
string
url
)
{
var
response
=
new
RedirectResponse
();
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
ResponseHeaders
.
Add
(
"Location"
,
new
Models
.
HttpHeader
(
"Location"
,
url
));
response
.
ResponseHeaders
.
Add
(
"Location"
,
new
HttpHeader
(
"Location"
,
url
));
response
.
ResponseBody
=
Encoding
.
ASCII
.
GetBytes
(
string
.
Empty
);
await
Respond
(
response
);
...
...
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
View file @
31edf6dd
using
System
;
namespace
Titanium.Web.Proxy.Exceptions
{
/// <summary>
...
...
@@ -7,6 +6,10 @@ namespace Titanium.Web.Proxy.Exceptions
/// </summary>
public
class
BodyNotFoundException
:
ProxyException
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="message"></param>
public
BodyNotFoundException
(
string
message
)
:
base
(
message
)
{
...
...
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
View file @
31edf6dd
...
...
@@ -2,6 +2,9 @@
namespace
Titanium.Web.Proxy.Extensions
{
/// <summary>
/// Extension methods for Byte Arrays.
/// </summary>
public
static
class
ByteArrayExtensions
{
/// <summary>
...
...
@@ -14,7 +17,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <returns></returns>
public
static
T
[]
SubArray
<
T
>(
this
T
[]
data
,
int
index
,
int
length
)
{
T
[]
result
=
new
T
[
length
];
var
result
=
new
T
[
length
];
Array
.
Copy
(
data
,
index
,
result
,
0
,
length
);
return
result
;
}
...
...
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
31edf6dd
...
...
@@ -12,11 +12,11 @@ namespace Titanium.Web.Proxy.Extensions
internal
static
bool
IsConnected
(
this
Socket
client
)
{
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
client
.
Blocking
;
var
blockingState
=
client
.
Blocking
;
try
{
byte
[]
tmp
=
new
byte
[
1
];
var
tmp
=
new
byte
[
1
];
client
.
Blocking
=
false
;
client
.
Send
(
tmp
,
0
,
0
);
...
...
@@ -25,14 +25,7 @@ namespace Titanium.Web.Proxy.Extensions
catch
(
SocketException
e
)
{
// 10035 == WSAEWOULDBLOCK
if
(
e
.
NativeErrorCode
.
Equals
(
10035
))
{
return
true
;
}
else
{
return
false
;
}
return
e
.
NativeErrorCode
.
Equals
(
10035
);
}
finally
{
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
31edf6dd
...
...
@@ -4,7 +4,6 @@ using System.IO;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Helpers
{
...
...
@@ -16,15 +15,15 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
internal
class
CustomBinaryReader
:
IDisposable
{
private
Stream
stream
;
private
Encoding
encoding
;
private
readonly
Stream
stream
;
private
readonly
Encoding
encoding
;
internal
CustomBinaryReader
(
Stream
stream
)
{
this
.
stream
=
stream
;
//default to UTF-8
this
.
encoding
=
Encoding
.
UTF8
;
encoding
=
Encoding
.
UTF8
;
}
internal
Stream
BaseStream
=>
stream
;
...
...
@@ -40,7 +39,7 @@ namespace Titanium.Web.Proxy.Helpers
var
lastChar
=
default
(
char
);
var
buffer
=
new
byte
[
1
];
while
((
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
1
))
>
0
)
while
((
await
stream
.
ReadAsync
(
buffer
,
0
,
1
))
>
0
)
{
//if new line
if
(
lastChar
==
'\r'
&&
buffer
[
0
]
==
'\n'
)
...
...
@@ -82,6 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Read the specified number of raw bytes from the base stream
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
int
bufferSize
,
long
totalBytesToRead
)
...
...
@@ -98,7 +98,7 @@ namespace Titanium.Web.Proxy.Helpers
using
(
var
outStream
=
new
MemoryStream
())
{
while
((
bytesRead
+=
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
while
((
bytesRead
+=
await
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
{
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
);
totalBytesRead
+=
bytesRead
;
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
31edf6dd
...
...
@@ -8,6 +8,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
public
class
FireFoxProxySettingsManager
{
/// <summary>
/// Add Firefox settings.
/// </summary>
public
void
AddFirefox
()
{
try
...
...
@@ -16,28 +19,27 @@ namespace Titanium.Web.Proxy.Helpers
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
if
(!
File
.
Exists
(
myFfPrefFile
))
return
;
// We have a pref file so let''s make sure it has the proxy setting
var
myReader
=
new
StreamReader
(
myFfPrefFile
);
var
myPrefContents
=
myReader
.
ReadToEnd
();
myReader
.
Close
();
if
(
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
{
if
(!
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
return
;
// Add the proxy enable line and write it back to the file
myPrefContents
=
myPrefContents
.
Replace
(
"user_pref(\"network.proxy.type\", 0);"
,
""
);
File
.
Delete
(
myFfPrefFile
);
File
.
WriteAllText
(
myFfPrefFile
,
myPrefContents
);
}
}
}
catch
(
Exception
)
{
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
}
}
/// <summary>
/// Remove firefox settings.
/// </summary>
public
void
RemoveFirefox
()
{
try
...
...
@@ -46,8 +48,7 @@ namespace Titanium.Web.Proxy.Helpers
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
if
(!
File
.
Exists
(
myFfPrefFile
))
return
;
// We have a pref file so let''s make sure it has the proxy setting
var
myReader
=
new
StreamReader
(
myFfPrefFile
);
var
myPrefContents
=
myReader
.
ReadToEnd
();
...
...
@@ -61,7 +62,6 @@ namespace Titanium.Web.Proxy.Helpers
File
.
WriteAllText
(
myFfPrefFile
,
myPrefContents
);
}
}
}
catch
(
Exception
)
{
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
...
...
Titanium.Web.Proxy/Helpers/Network.cs
View file @
31edf6dd
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Helpers
{
...
...
@@ -33,28 +29,14 @@ namespace Titanium.Web.Proxy.Helpers
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address></param>
/// <param name="address
"
></param>
/// <returns></returns>
internal
static
bool
IsLocalIpAddress
(
IPAddress
address
)
{
try
{
// get local IP addresses
IPAddress
[]
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
var
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
// test if any host IP equals to any local IP or to localhost
// is localhost
if
(
IPAddress
.
IsLoopback
(
address
))
return
true
;
// is local address
foreach
(
IPAddress
localIP
in
localIPs
)
{
if
(
address
.
Equals
(
localIP
))
return
true
;
}
}
catch
{
}
return
false
;
return
IPAddress
.
IsLoopback
(
address
)
||
localIPs
.
Contains
(
address
);
}
}
}
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
31edf6dd
...
...
@@ -4,11 +4,8 @@ using Microsoft.Win32;
using
System.Text.RegularExpressions
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net.Sockets
;
/// <summary>
/// Helper classes for setting system proxy settings
/// </summary>
// Helper classes for setting system proxy settings
namespace
Titanium.Web.Proxy.Helpers
{
internal
enum
ProxyProtocolType
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
31edf6dd
...
...
@@ -140,6 +140,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="clientStream"></param>
/// <param name="tcpConnectionFactory"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
internal
static
async
Task
SendRaw
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
string
remoteHostName
,
int
remotePort
,
string
httpCmd
,
Version
httpVersion
,
Dictionary
<
string
,
HttpHeader
>
requestHeaders
,
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
31edf6dd
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Shared
;
...
...
@@ -15,17 +13,26 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
class
HttpWebClient
{
/// <summary>
/// Connection to server
/// </summary>
internal
TcpConnection
ServerConnection
{
get
;
set
;
}
public
Guid
RequestId
{
get
;
private
set
;
}
/// <summary>
/// Request ID.
/// </summary>
public
Guid
RequestId
{
get
;
}
/// <summary>
/// Headers passed with Connect.
/// </summary>
public
List
<
HttpHeader
>
ConnectHeaders
{
get
;
set
;
}
/// <summary>
/// Web Request.
/// </summary>
public
Request
Request
{
get
;
set
;
}
/// <summary>
/// Web Response.
/// </summary>
public
Response
Response
{
get
;
set
;
}
/// <summary>
...
...
@@ -37,15 +44,14 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Is Https?
/// </summary>
public
bool
IsHttps
=>
this
.
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
public
bool
IsHttps
=>
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
internal
HttpWebClient
()
{
this
.
RequestId
=
Guid
.
NewGuid
();
this
.
Request
=
new
Request
();
this
.
Response
=
new
Response
();
RequestId
=
Guid
.
NewGuid
();
Request
=
new
Request
();
Response
=
new
Response
();
}
/// <summary>
...
...
@@ -65,18 +71,18 @@ namespace Titanium.Web.Proxy.Http
/// <returns></returns>
internal
async
Task
SendRequest
(
bool
enable100ContinueBehaviour
)
{
Stream
stream
=
ServerConnection
.
Stream
;
var
stream
=
ServerConnection
.
Stream
;
StringBuilde
r
requestLines
=
new
StringBuilder
();
va
r
requestLines
=
new
StringBuilder
();
//prepare the request & headers
if
((
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
)
||
(
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
==
true
))
if
((
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
)
||
(
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
))
{
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
this
.
Request
.
Method
,
this
.
Request
.
RequestUri
.
AbsoluteUri
,
$"HTTP/
{
this
.
Request
.
HttpVersion
.
Major
}
.
{
this
.
Request
.
HttpVersion
.
Minor
}
"
));
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
Request
.
Method
,
Request
.
RequestUri
.
AbsoluteUri
,
$"HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
));
}
else
{
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
this
.
Request
.
Method
,
this
.
Request
.
RequestUri
.
PathAndQuery
,
$"HTTP/
{
this
.
Request
.
HttpVersion
.
Major
}
.
{
this
.
Request
.
HttpVersion
.
Minor
}
"
));
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
Request
.
Method
,
Request
.
RequestUri
.
PathAndQuery
,
$"HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
));
}
//Send Authentication to Upstream proxy if needed
...
...
@@ -86,7 +92,7 @@ namespace Titanium.Web.Proxy.Http
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
ServerConnection
.
UpStreamHttpProxy
.
UserName
+
":"
+
ServerConnection
.
UpStreamHttpProxy
.
Password
)));
}
//write request headers
foreach
(
var
headerItem
in
this
.
Request
.
RequestHeaders
)
foreach
(
var
headerItem
in
Request
.
RequestHeaders
)
{
var
header
=
headerItem
.
Value
;
if
(
headerItem
.
Key
!=
"Proxy-Authorization"
)
...
...
@@ -96,7 +102,7 @@ namespace Titanium.Web.Proxy.Http
}
//write non unique request headers
foreach
(
var
headerItem
in
this
.
Request
.
NonUniqueRequestHeaders
)
foreach
(
var
headerItem
in
Request
.
NonUniqueRequestHeaders
)
{
var
headers
=
headerItem
.
Value
;
foreach
(
var
header
in
headers
)
...
...
@@ -110,15 +116,15 @@ namespace Titanium.Web.Proxy.Http
requestLines
.
AppendLine
();
string
request
=
requestLines
.
ToString
();
byte
[]
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
var
request
=
requestLines
.
ToString
();
var
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
await
stream
.
WriteAsync
(
requestBytes
,
0
,
requestBytes
.
Length
);
await
stream
.
FlushAsync
();
if
(
enable100ContinueBehaviour
)
{
if
(
this
.
Request
.
ExpectContinue
)
if
(
Request
.
ExpectContinue
)
{
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
var
responseStatusCode
=
httpResult
[
1
].
Trim
();
...
...
@@ -128,13 +134,13 @@ namespace Titanium.Web.Proxy.Http
if
(
responseStatusCode
.
Equals
(
"100"
)
&&
responseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
{
this
.
Request
.
Is100Continue
=
true
;
Request
.
Is100Continue
=
true
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
}
else
if
(
responseStatusCode
.
Equals
(
"417"
)
&&
responseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
{
this
.
Request
.
ExpectationFailed
=
true
;
Request
.
ExpectationFailed
=
true
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
}
}
...
...
@@ -148,7 +154,7 @@ namespace Titanium.Web.Proxy.Http
internal
async
Task
ReceiveResponse
()
{
//return if this is already read
if
(
this
.
Response
.
ResponseStatusCode
!=
null
)
return
;
if
(
Response
.
ResponseStatusCode
!=
null
)
return
;
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
...
...
@@ -161,33 +167,33 @@ namespace Titanium.Web.Proxy.Http
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
version
=
new
Version
(
1
,
1
);
if
(
httpVersion
==
"http/1.0"
)
if
(
0
==
string
.
CompareOrdinal
(
httpVersion
,
"http/1.0"
)
)
{
version
=
new
Version
(
1
,
0
);
}
this
.
Response
.
HttpVersion
=
version
;
this
.
Response
.
ResponseStatusCode
=
httpResult
[
1
].
Trim
();
this
.
Response
.
ResponseStatusDescription
=
httpResult
[
2
].
Trim
();
Response
.
HttpVersion
=
version
;
Response
.
ResponseStatusCode
=
httpResult
[
1
].
Trim
();
Response
.
ResponseStatusDescription
=
httpResult
[
2
].
Trim
();
//For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
if
(
this
.
Response
.
ResponseStatusCode
.
Equals
(
"100"
)
&&
this
.
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
if
(
Response
.
ResponseStatusCode
.
Equals
(
"100"
)
&&
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
{
//Read the next line after 100-continue
this
.
Response
.
Is100Continue
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
Response
.
Is100Continue
=
true
;
Response
.
ResponseStatusCode
=
null
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
//now receive response
await
ReceiveResponse
();
return
;
}
else
if
(
this
.
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
&&
this
.
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
else
if
(
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
&&
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
{
//read next line after expectation failed response
this
.
Response
.
ExpectationFailed
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
Response
.
ExpectationFailed
=
true
;
Response
.
ResponseStatusCode
=
null
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
//now receive response
await
ReceiveResponse
();
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
31edf6dd
...
...
@@ -34,12 +34,7 @@ namespace Titanium.Web.Proxy.Http
get
{
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"host"
);
if
(
hasHeader
)
{
return
RequestHeaders
[
"host"
].
Value
;
}
return
null
;
return
hasHeader
?
RequestHeaders
[
"host"
].
Value
:
null
;
}
set
{
...
...
@@ -154,11 +149,11 @@ namespace Titanium.Web.Proxy.Http
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"content-type"
];
header
.
Value
=
value
.
ToString
()
;
header
.
Value
=
value
;
}
else
{
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
.
ToString
()
));
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
));
}
}
...
...
@@ -219,15 +214,11 @@ namespace Titanium.Web.Proxy.Http
{
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"expect"
);
if
(
hasHeader
)
{
if
(!
hasHeader
)
return
false
;
var
header
=
RequestHeaders
[
"expect"
];
return
header
.
Value
.
Equals
(
"100-continue"
);
}
return
false
;
}
}
/// <summary>
...
...
@@ -275,13 +266,7 @@ namespace Titanium.Web.Proxy.Http
var
header
=
RequestHeaders
[
"upgrade"
];
if
(
header
.
Value
.
ToLower
()
==
"websocket"
)
{
return
true
;
}
return
false
;
return
header
.
Value
.
ToLower
()
==
"websocket"
;
}
}
...
...
@@ -305,6 +290,9 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
/// <summary>
/// Constructor.
/// </summary>
public
Request
()
{
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
31edf6dd
...
...
@@ -12,7 +12,13 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
class
Response
{
/// <summary>
/// Response Status Code.
/// </summary>
public
string
ResponseStatusCode
{
get
;
set
;
}
/// <summary>
/// Response Status description.
/// </summary>
public
string
ResponseStatusDescription
{
get
;
set
;
}
internal
Encoding
Encoding
=>
this
.
GetResponseCharacterEncoding
();
...
...
@@ -26,15 +32,11 @@ namespace Titanium.Web.Proxy.Http
{
var
hasHeader
=
ResponseHeaders
.
ContainsKey
(
"content-encoding"
);
if
(
hasHeader
)
{
if
(!
hasHeader
)
return
null
;
var
header
=
ResponseHeaders
[
"content-encoding"
];
return
header
.
Value
.
Trim
();
}
return
null
;
}
}
internal
Version
HttpVersion
{
get
;
set
;
}
...
...
@@ -229,10 +231,13 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
/// <summary>
/// Constructor.
/// </summary>
public
Response
()
{
this
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
this
.
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
...
...
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
View file @
31edf6dd
...
...
@@ -7,16 +7,25 @@ namespace Titanium.Web.Proxy.Http.Responses
/// </summary>
public
class
GenericResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="status"></param>
public
GenericResponse
(
HttpStatusCode
status
)
{
ResponseStatusCode
=
((
int
)
status
).
ToString
();
ResponseStatusDescription
=
status
.
ToString
();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="statusCode"></param>
/// <param name="statusDescription"></param>
public
GenericResponse
(
string
statusCode
,
string
statusDescription
)
{
ResponseStatusCode
=
statusCode
;
ResponseStatusDescription
=
statusCode
;
ResponseStatusDescription
=
statusDescription
;
}
}
}
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
View file @
31edf6dd
...
...
@@ -5,6 +5,9 @@
/// </summary>
public
sealed
class
OkResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
public
OkResponse
()
{
ResponseStatusCode
=
"200"
;
...
...
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
View file @
31edf6dd
...
...
@@ -5,6 +5,9 @@
/// </summary>
public
sealed
class
RedirectResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
public
RedirectResponse
()
{
ResponseStatusCode
=
"302"
;
...
...
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
31edf6dd
...
...
@@ -10,20 +10,38 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
abstract
class
ProxyEndPoint
{
public
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
protected
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
{
this
.
IpAddress
=
IpAddress
;
this
.
Port
=
Port
;
this
.
EnableSsl
=
EnableSsl
;
}
/// <summary>
/// Ip Address.
/// </summary>
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
/// <summary>
/// Port.
/// </summary>
public
int
Port
{
get
;
internal
set
;
}
/// <summary>
/// Enable SSL?
/// </summary>
public
bool
EnableSsl
{
get
;
internal
set
;
}
public
bool
IpV6Enabled
=>
IpAddress
==
IPAddress
.
IPv6Any
||
IpAddress
==
IPAddress
.
IPv6Loopback
||
IpAddress
==
IPAddress
.
IPv6None
;
/// <summary>
/// Is IPv6 enabled?
/// </summary>
public
bool
IpV6Enabled
=>
Equals
(
IpAddress
,
IPAddress
.
IPv6Any
)
||
Equals
(
IpAddress
,
IPAddress
.
IPv6Loopback
)
||
Equals
(
IpAddress
,
IPAddress
.
IPv6None
);
internal
TcpListener
listener
{
get
;
set
;
}
}
...
...
@@ -37,10 +55,22 @@ namespace Titanium.Web.Proxy.Models
internal
bool
IsSystemHttpProxy
{
get
;
set
;
}
internal
bool
IsSystemHttpsProxy
{
get
;
set
;
}
/// <summary>
/// List of host names to exclude using Regular Expressions.
/// </summary>
public
List
<
string
>
ExcludedHttpsHostNameRegex
{
get
;
set
;
}
/// <summary>
/// Generic certificate to use for SSL decryption.
/// </summary>
public
X509Certificate2
GenericCertificate
{
get
;
set
;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
public
ExplicitProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
...
...
@@ -54,13 +84,19 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
//This is valid only when UseServerNameIndication is set to false
public
string
GenericCertificateName
{
get
;
set
;
}
// public bool UseServerNameIndication { get; set; }
/// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public
string
GenericCertificateName
{
get
;
set
;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
public
TransparentProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
...
...
Titanium.Web.Proxy/Models/ExternalProxy.cs
View file @
31edf6dd
...
...
@@ -13,10 +13,16 @@ namespace Titanium.Web.Proxy.Models
private
string
userName
;
private
string
password
;
/// <summary>
/// Use default windows credentials?
/// </summary>
public
bool
UseDefaultCredentials
{
get
;
set
;
}
/// <summary>
/// Username.
/// </summary>
public
string
UserName
{
get
{
return
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
UserName
:
userName
;
}
get
=>
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
UserName
:
userName
;
set
{
userName
=
value
;
...
...
@@ -28,9 +34,12 @@ namespace Titanium.Web.Proxy.Models
}
}
/// <summary>
/// Password.
/// </summary>
public
string
Password
{
get
{
return
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
Password
:
password
;
}
get
=>
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
Password
:
password
;
set
{
password
=
value
;
...
...
@@ -42,7 +51,13 @@ namespace Titanium.Web.Proxy.Models
}
}
/// <summary>
/// Host name.
/// </summary>
public
string
HostName
{
get
;
set
;
}
/// <summary>
/// Port.
/// </summary>
public
int
Port
{
get
;
set
;
}
}
}
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
31edf6dd
...
...
@@ -7,6 +7,12 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
HttpHeader
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <exception cref="Exception"></exception>
public
HttpHeader
(
string
name
,
string
value
)
{
if
(
string
.
IsNullOrEmpty
(
name
))
...
...
@@ -18,7 +24,13 @@ namespace Titanium.Web.Proxy.Models
Value
=
value
.
Trim
();
}
/// <summary>
/// Header Name.
/// </summary>
public
string
Name
{
get
;
set
;
}
/// <summary>
/// Header Value.
/// </summary>
public
string
Value
{
get
;
set
;
}
/// <summary>
...
...
@@ -27,7 +39,7 @@ namespace Titanium.Web.Proxy.Models
/// <returns></returns>
public
override
string
ToString
()
{
return
string
.
Format
(
"{0}: {1}"
,
Name
,
Value
)
;
return
$"
{
Name
}
:
{
Value
}
"
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/CertificateMaker.cs
View file @
31edf6dd
...
...
@@ -6,187 +6,197 @@ using System.Threading;
namespace
Titanium.Web.Proxy.Network
{
/// <summary>
/// Certificate Maker - uses MakeCert
/// </summary>
public
class
CertificateMaker
{
private
Type
typeX500DN
;
private
readonly
Type
typeX500DN
;
private
Type
typeX509PrivateKey
;
private
readonly
Type
typeX509PrivateKey
;
private
Type
typeOID
;
private
readonly
Type
typeOID
;
private
Type
typeOIDS
;
private
readonly
Type
typeOIDS
;
private
Type
typeKUExt
;
private
readonly
Type
typeKUExt
;
private
Type
typeEKUExt
;
private
readonly
Type
typeEKUExt
;
private
Type
typeRequestCert
;
private
readonly
Type
typeRequestCert
;
private
Type
typeX509Extensions
;
private
readonly
Type
typeX509Extensions
;
private
Type
typeBasicConstraints
;
private
readonly
Type
typeBasicConstraints
;
private
Type
typeSignerCertificate
;
private
readonly
Type
typeSignerCertificate
;
private
Type
typeX509Enrollment
;
private
readonly
Type
typeX509Enrollment
;
private
Type
typeAlternativeName
;
//
private Type typeAlternativeName;
private
Type
typeAlternativeNames
;
//
private Type typeAlternativeNames;
private
Type
typeAlternativeNamesExt
;
//
private Type typeAlternativeNamesExt;
private
string
sProviderName
=
"Microsoft Enhanced Cryptographic Provider v1.0"
;
private
readonly
string
sProviderName
=
"Microsoft Enhanced Cryptographic Provider v1.0"
;
private
object
_SharedPrivateKey
;
/// <summary>
/// Constructor.
/// </summary>
public
CertificateMaker
()
{
this
.
typeX500DN
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX500DistinguishedName"
,
true
);
this
.
typeX509PrivateKey
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509PrivateKey"
,
true
);
this
.
typeOID
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CObjectId"
,
true
);
this
.
typeOIDS
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CObjectIds.1"
,
true
);
this
.
typeEKUExt
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionEnhancedKeyUsage"
);
this
.
typeKUExt
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionKeyUsage"
);
this
.
typeRequestCert
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509CertificateRequestCertificate"
);
this
.
typeX509Extensions
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509Extensions"
);
this
.
typeBasicConstraints
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionBasicConstraints"
);
this
.
typeSignerCertificate
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CSignerCertificate"
);
this
.
typeX509Enrollment
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509Enrollment"
);
this
.
typeAlternativeName
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CAlternativeName"
);
this
.
typeAlternativeNames
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CAlternativeNames"
);
this
.
typeAlternativeNamesExt
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionAlternativeNames"
);
}
typeX500DN
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX500DistinguishedName"
,
true
);
typeX509PrivateKey
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509PrivateKey"
,
true
);
typeOID
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CObjectId"
,
true
);
typeOIDS
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CObjectIds.1"
,
true
);
typeEKUExt
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionEnhancedKeyUsage"
);
typeKUExt
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionKeyUsage"
);
typeRequestCert
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509CertificateRequestCertificate"
);
typeX509Extensions
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509Extensions"
);
typeBasicConstraints
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509ExtensionBasicConstraints"
);
typeSignerCertificate
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CSignerCertificate"
);
typeX509Enrollment
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509Enrollment"
);
//this.typeAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName");
//this.typeAlternativeNames = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames");
//this.typeAlternativeNamesExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames");
}
/// <summary>
/// Make certificate.
/// </summary>
/// <param name="sSubjectCN"></param>
/// <param name="isRoot"></param>
/// <param name="signingCert"></param>
/// <returns></returns>
public
X509Certificate2
MakeCertificate
(
string
sSubjectCN
,
bool
isRoot
,
X509Certificate2
signingCert
=
null
)
{
return
this
.
MakeCertificateInternal
(
sSubjectCN
,
isRoot
,
true
,
signingCert
);
return
MakeCertificateInternal
(
sSubjectCN
,
isRoot
,
true
,
signingCert
);
}
private
X509Certificate2
MakeCertificate
(
bool
IsRoot
,
string
SubjectCN
,
string
FullSubject
,
int
PrivateKeyLength
,
string
HashAlg
,
DateTime
ValidFrom
,
DateTime
ValidTo
,
X509Certificate2
SigningCertificate
)
private
X509Certificate2
MakeCertificate
(
bool
IsRoot
,
string
FullSubject
,
int
PrivateKeyLength
,
string
HashAlg
,
DateTime
ValidFrom
,
DateTime
ValidTo
,
X509Certificate2
SigningCertificate
)
{
X509Certificate2
cert
;
if
(
IsRoot
!=
(
null
==
SigningCertificate
))
{
throw
new
ArgumentException
(
"You must specify a Signing Certificate if and only if you are not creating a root."
,
"oSigningCertificate"
);
throw
new
ArgumentException
(
"You must specify a Signing Certificate if and only if you are not creating a root."
,
nameof
(
IsRoot
)
);
}
object
x500DN
=
Activator
.
CreateInstance
(
this
.
typeX500DN
);
object
[]
subject
=
new
object
[]
{
FullSubject
,
0
};
t
his
.
t
ypeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500DN
,
subject
);
object
x500DN2
=
Activator
.
CreateInstance
(
this
.
typeX500DN
);
var
x500DN
=
Activator
.
CreateInstance
(
typeX500DN
);
var
subject
=
new
object
[]
{
FullSubject
,
0
};
typeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500DN
,
subject
);
var
x500DN2
=
Activator
.
CreateInstance
(
typeX500DN
);
if
(!
IsRoot
)
{
subject
[
0
]
=
SigningCertificate
.
Subject
;
}
t
his
.
t
ypeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500DN2
,
subject
);
typeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500DN2
,
subject
);
object
sharedPrivateKey
=
null
;
if
(!
IsRoot
)
{
sharedPrivateKey
=
this
.
_SharedPrivateKey
;
sharedPrivateKey
=
_SharedPrivateKey
;
}
if
(
sharedPrivateKey
==
null
)
{
sharedPrivateKey
=
Activator
.
CreateInstance
(
t
his
.
t
ypeX509PrivateKey
);
subject
=
new
object
[]
{
this
.
sProviderName
};
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"ProviderName"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
sharedPrivateKey
=
Activator
.
CreateInstance
(
typeX509PrivateKey
);
subject
=
new
object
[]
{
sProviderName
};
typeX509PrivateKey
.
InvokeMember
(
"ProviderName"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
subject
[
0
]
=
2
;
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"ExportPolicy"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
typeX509PrivateKey
.
InvokeMember
(
"ExportPolicy"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
subject
=
new
object
[]
{
(
IsRoot
?
2
:
1
)
};
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"KeySpec"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
typeX509PrivateKey
.
InvokeMember
(
"KeySpec"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
if
(!
IsRoot
)
{
subject
=
new
object
[]
{
176
};
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"KeyUsage"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
typeX509PrivateKey
.
InvokeMember
(
"KeyUsage"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
}
subject
[
0
]
=
PrivateKeyLength
;
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"Length"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
t
his
.
t
ypeX509PrivateKey
.
InvokeMember
(
"Create"
,
BindingFlags
.
InvokeMethod
,
null
,
sharedPrivateKey
,
null
);
typeX509PrivateKey
.
InvokeMember
(
"Length"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
subject
);
typeX509PrivateKey
.
InvokeMember
(
"Create"
,
BindingFlags
.
InvokeMethod
,
null
,
sharedPrivateKey
,
null
);
if
(!
IsRoot
)
{
this
.
_SharedPrivateKey
=
sharedPrivateKey
;
_SharedPrivateKey
=
sharedPrivateKey
;
}
}
subject
=
new
object
[
1
];
object
obj3
=
Activator
.
CreateInstance
(
this
.
typeOID
);
var
obj3
=
Activator
.
CreateInstance
(
typeOID
);
subject
[
0
]
=
"1.3.6.1.5.5.7.3.1"
;
t
his
.
t
ypeOID
.
InvokeMember
(
"InitializeFromValue"
,
BindingFlags
.
InvokeMethod
,
null
,
obj3
,
subject
);
object
obj4
=
Activator
.
CreateInstance
(
this
.
typeOIDS
);
typeOID
.
InvokeMember
(
"InitializeFromValue"
,
BindingFlags
.
InvokeMethod
,
null
,
obj3
,
subject
);
var
obj4
=
Activator
.
CreateInstance
(
typeOIDS
);
subject
[
0
]
=
obj3
;
t
his
.
t
ypeOIDS
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj4
,
subject
);
object
obj5
=
Activator
.
CreateInstance
(
this
.
typeEKUExt
);
typeOIDS
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj4
,
subject
);
var
obj5
=
Activator
.
CreateInstance
(
typeEKUExt
);
subject
[
0
]
=
obj4
;
t
his
.
t
ypeEKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj5
,
subject
);
object
obj6
=
Activator
.
CreateInstance
(
this
.
typeRequestCert
);
subject
=
new
object
[]
{
1
,
sharedPrivateKey
,
string
.
Empty
};
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
obj6
,
subject
);
subject
=
new
object
[]
{
x500DN
};
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
typeEKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj5
,
subject
);
var
obj6
=
Activator
.
CreateInstance
(
typeRequestCert
);
subject
=
new
[]
{
1
,
sharedPrivateKey
,
string
.
Empty
};
typeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
obj6
,
subject
);
subject
=
new
[]
{
x500DN
};
typeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
subject
[
0
]
=
x500DN
;
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
typeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
subject
[
0
]
=
ValidFrom
;
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"NotBefore"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
typeRequestCert
.
InvokeMember
(
"NotBefore"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
subject
[
0
]
=
ValidTo
;
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"NotAfter"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
object
obj7
=
Activator
.
CreateInstance
(
this
.
typeKUExt
);
typeRequestCert
.
InvokeMember
(
"NotAfter"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
var
obj7
=
Activator
.
CreateInstance
(
typeKUExt
);
subject
[
0
]
=
176
;
t
his
.
t
ypeKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj7
,
subject
);
object
obj8
=
this
.
typeRequestCert
.
InvokeMember
(
"X509Extensions"
,
BindingFlags
.
GetProperty
,
null
,
obj6
,
null
);
typeKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj7
,
subject
);
var
obj8
=
typeRequestCert
.
InvokeMember
(
"X509Extensions"
,
BindingFlags
.
GetProperty
,
null
,
obj6
,
null
);
subject
=
new
object
[
1
];
if
(!
IsRoot
)
{
subject
[
0
]
=
obj7
;
t
his
.
t
ypeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
}
subject
[
0
]
=
obj5
;
t
his
.
t
ypeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
if
(!
IsRoot
)
{
object
obj12
=
Activator
.
CreateInstance
(
this
.
typeSignerCertificate
);
var
obj12
=
Activator
.
CreateInstance
(
typeSignerCertificate
);
subject
=
new
object
[]
{
0
,
0
,
12
,
SigningCertificate
.
Thumbprint
};
t
his
.
t
ypeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
obj12
,
subject
);
subject
=
new
object
[]
{
obj12
};
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
typeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
obj12
,
subject
);
subject
=
new
[]
{
obj12
};
typeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
}
else
{
object
obj13
=
Activator
.
CreateInstance
(
this
.
typeBasicConstraints
);
var
obj13
=
Activator
.
CreateInstance
(
typeBasicConstraints
);
subject
=
new
object
[]
{
"true"
,
"0"
};
t
his
.
t
ypeBasicConstraints
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj13
,
subject
);
subject
=
new
object
[]
{
obj13
};
t
his
.
t
ypeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
typeBasicConstraints
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj13
,
subject
);
subject
=
new
[]
{
obj13
};
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
obj8
,
subject
);
}
object
obj14
=
Activator
.
CreateInstance
(
this
.
typeOID
);
var
obj14
=
Activator
.
CreateInstance
(
typeOID
);
subject
=
new
object
[]
{
1
,
0
,
0
,
HashAlg
};
t
his
.
t
ypeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
obj14
,
subject
);
subject
=
new
object
[]
{
obj14
};
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
t
his
.
t
ypeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj6
,
null
);
object
obj15
=
Activator
.
CreateInstance
(
this
.
typeX509Enrollment
);
typeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
obj14
,
subject
);
subject
=
new
[]
{
obj14
};
typeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
obj6
,
subject
);
typeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
obj6
,
null
);
var
obj15
=
Activator
.
CreateInstance
(
typeX509Enrollment
);
subject
[
0
]
=
obj6
;
t
his
.
t
ypeX509Enrollment
.
InvokeMember
(
"InitializeFromRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
typeX509Enrollment
.
InvokeMember
(
"InitializeFromRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
if
(
IsRoot
)
{
subject
[
0
]
=
"DO_NOT_TRUST_TitaniumProxy-CE"
;
t
his
.
t
ypeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
obj15
,
subject
);
typeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
obj15
,
subject
);
}
subject
[
0
]
=
0
;
object
obj16
=
this
.
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
subject
=
new
object
[]
{
2
,
obj16
,
0
,
string
.
Empty
};
t
his
.
t
ypeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
var
obj16
=
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
subject
=
new
[]
{
2
,
obj16
,
0
,
string
.
Empty
};
typeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
subject
=
new
object
[]
{
null
,
0
,
1
};
string
empty
=
string
.
Empty
;
try
{
empty
=
(
string
)
this
.
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
var
empty
=
(
string
)
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
obj15
,
subject
);
return
new
X509Certificate2
(
Convert
.
FromBase64String
(
empty
),
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
}
catch
(
Exception
exception1
)
catch
(
Exception
)
{
Exception
exception
=
exception1
;
cert
=
null
;
// ignored
}
return
cert
;
return
null
;
}
private
X509Certificate2
MakeCertificateInternal
(
string
sSubjectCN
,
bool
isRoot
,
bool
switchToMTAIfNeeded
,
X509Certificate2
signingCert
=
null
)
...
...
@@ -194,39 +204,26 @@ namespace Titanium.Web.Proxy.Network
X509Certificate2
rCert
=
null
;
if
(
switchToMTAIfNeeded
&&
Thread
.
CurrentThread
.
GetApartmentState
()
!=
ApartmentState
.
MTA
)
{
ManualResetEvent
manualResetEvent
=
new
ManualResetEvent
(
false
);
ThreadPool
.
QueueUserWorkItem
(
(
object
o
)
=>
var
manualResetEvent
=
new
ManualResetEvent
(
false
);
ThreadPool
.
QueueUserWorkItem
(
o
=>
{
rCert
=
this
.
MakeCertificateInternal
(
sSubjectCN
,
isRoot
,
false
,
signingCert
);
rCert
=
MakeCertificateInternal
(
sSubjectCN
,
isRoot
,
false
,
signingCert
);
manualResetEvent
.
Set
();
});
manualResetEvent
.
WaitOne
();
manualResetEvent
.
Close
();
return
rCert
;
}
string
fullSubject
=
string
.
Format
(
"CN={0}{1}"
,
sSubjectCN
,
""
)
;
//Subject
string
HashAlgo
=
"SHA256"
;
//Sig Algo
int
GraceDays
=
-
366
;
//Grace Days
int
ValidDays
=
1825
;
//ValiDays
int
keyLength
=
2048
;
//KeyLength
var
fullSubject
=
$"CN=
{
sSubjectCN
}
"
;
//Subject
var
HashAlgo
=
"SHA256"
;
//Sig Algo
var
GraceDays
=
-
366
;
//Grace Days
var
ValidDays
=
1825
;
//ValiDays
var
keyLength
=
2048
;
//KeyLength
DateTime
graceTime
=
DateTime
.
Now
.
AddDays
((
double
)
GraceDays
);
DateTime
now
=
DateTime
.
Now
;
try
{
if
(!
isRoot
)
{
rCert
=
this
.
MakeCertificate
(
false
,
sSubjectCN
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
((
double
)
ValidDays
),
signingCert
);
}
else
{
rCert
=
this
.
MakeCertificate
(
true
,
sSubjectCN
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
((
double
)
ValidDays
),
null
);
}
}
catch
(
Exception
e
)
{
throw
e
;
}
var
graceTime
=
DateTime
.
Now
.
AddDays
(
GraceDays
);
var
now
=
DateTime
.
Now
;
rCert
=
!
isRoot
?
MakeCertificate
(
false
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
(
ValidDays
),
signingCert
)
:
MakeCertificate
(
true
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
(
ValidDays
),
null
);
return
rCert
;
}
}
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
31edf6dd
...
...
@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal
class
CertificateManager
:
IDisposable
{
private
CertificateMaker
certEngine
=
null
;
private
readonly
CertificateMaker
certEngine
;
private
bool
clearCertificates
{
get
;
set
;
}
/// <summary>
...
...
@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
private
readonly
IDictionary
<
string
,
CachedCertificate
>
certificateCache
;
private
Action
<
Exception
>
exceptionFunc
;
private
readonly
Action
<
Exception
>
exceptionFunc
;
internal
string
Issuer
{
get
;
private
set
;
}
internal
string
RootCertificateName
{
get
;
private
set
;
}
internal
string
Issuer
{
get
;
}
internal
string
RootCertificateName
{
get
;
}
internal
X509Certificate2
rootCertificate
{
get
;
set
;
}
...
...
@@ -42,10 +42,11 @@ namespace Titanium.Web.Proxy.Network
internal
X509Certificate2
GetRootCertificate
()
{
var
fileName
=
Path
.
Combine
(
System
.
IO
.
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
),
"rootCert.pfx"
);
var
path
=
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
);
if
(
null
==
path
)
throw
new
NullReferenceException
();
var
fileName
=
Path
.
Combine
(
path
,
"rootCert.pfx"
);
if
(
File
.
Exists
(
fileName
))
{
if
(!
File
.
Exists
(
fileName
))
return
null
;
try
{
return
new
X509Certificate2
(
fileName
,
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
...
...
@@ -57,8 +58,6 @@ namespace Titanium.Web.Proxy.Network
return
null
;
}
}
return
null
;
}
/// <summary>
/// Attempts to create a RootCertificate
/// </summary>
...
...
@@ -75,7 +74,7 @@ namespace Titanium.Web.Proxy.Network
{
rootCertificate
=
CreateCertificate
(
RootCertificateName
,
true
);
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
...
...
@@ -83,38 +82,36 @@ namespace Titanium.Web.Proxy.Network
{
try
{
var
fileName
=
Path
.
Combine
(
System
.
IO
.
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
),
"rootCert.pfx"
);
var
path
=
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
);
if
(
null
==
path
)
throw
new
NullReferenceException
();
var
fileName
=
Path
.
Combine
(
path
,
"rootCert.pfx"
);
File
.
WriteAllBytes
(
fileName
,
rootCertificate
.
Export
(
X509ContentType
.
Pkcs12
));
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
}
return
rootCertificate
!=
null
;
}
/// <summary>
/// Create an SSL certificate
/// </summary>
/// <param name="store"></param>
/// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param>
/// <returns></returns>
internal
virtual
X509Certificate2
CreateCertificate
(
string
certificateName
,
bool
isRootCertificate
)
{
try
{
if
(
certificateCache
.
ContainsKey
(
certificateName
))
{
var
cached
=
certificateCache
[
certificateName
];
cached
.
LastAccess
=
DateTime
.
Now
;
return
cached
.
Certificate
;
}
}
catch
{
}
X509Certificate2
certificate
=
null
;
lock
(
string
.
Intern
(
certificateName
))
{
...
...
@@ -124,7 +121,7 @@ namespace Titanium.Web.Proxy.Network
{
certificate
=
certEngine
.
MakeCertificate
(
certificateName
,
isRootCertificate
,
rootCertificate
);
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
...
...
@@ -165,9 +162,6 @@ namespace Titanium.Web.Proxy.Network
{
clearCertificates
=
true
;
while
(
clearCertificates
)
{
try
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
certificateCacheTimeOutMinutes
);
...
...
@@ -177,10 +171,6 @@ namespace Titanium.Web.Proxy.Network
foreach
(
var
cache
in
outdated
)
certificateCache
.
Remove
(
cache
.
Key
);
}
finally
{
}
//after a minute come back to check for outdated certificates in cache
await
Task
.
Delay
(
1000
*
60
);
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
View file @
31edf6dd
...
...
@@ -47,6 +47,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
LastAccess
=
DateTime
.
Now
;
}
/// <summary>
/// Dispose.
/// </summary>
public
void
Dispose
()
{
Stream
.
Close
();
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
31edf6dd
...
...
@@ -19,14 +19,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal
class
TcpConnectionFactory
{
/// <summary>
/// Creates a TCP connection to server
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="httpCmd"></param>
/// <param name="httpVersion"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
...
...
@@ -69,7 +67,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if
(!
string
.
IsNullOrEmpty
(
externalHttpsProxy
.
UserName
)
&&
externalHttpsProxy
.
Password
!=
null
)
{
await
writer
.
WriteLineAsync
(
"Proxy-Connection: keep-alive"
);
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
System
.
Text
.
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
}
await
writer
.
WriteLineAsync
();
await
writer
.
FlushAsync
();
...
...
@@ -81,7 +79,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
var
result
=
await
reader
.
ReadLineAsync
();
if
(!
new
string
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
{
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
View file @
31edf6dd
...
...
@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Gets the local end point.
/// </summary>
public
IPEndPoint
LocalEndPoint
{
get
;
private
set
;
}
public
IPEndPoint
LocalEndPoint
{
get
;
}
/// <summary>
/// Gets the remote end point.
/// </summary>
public
IPEndPoint
RemoteEndPoint
{
get
;
private
set
;
}
public
IPEndPoint
RemoteEndPoint
{
get
;
}
/// <summary>
/// Gets the process identifier.
/// </summary>
public
int
ProcessId
{
get
;
private
set
;
}
public
int
ProcessId
{
get
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
View file @
31edf6dd
...
...
@@ -6,7 +6,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Represents collection of TcpRows
/// </summary>
/// <seealso cref="System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}" />
/// <seealso>
/// <cref>System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}</cref>
/// </seealso>
internal
class
TcpTable
:
IEnumerable
<
TcpRow
>
{
private
readonly
IEnumerable
<
TcpRow
>
tcpRows
;
...
...
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
31edf6dd
...
...
@@ -24,32 +24,46 @@ namespace Titanium.Web.Proxy
try
{
if
(
!
httpHeaders
.
Where
(
t
=>
t
.
Name
==
"Proxy-Authorization"
).
Any
(
))
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
{
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Required"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
}
else
{
var
headerValue
=
httpHeaders
.
Where
(
t
=>
t
.
Name
==
"Proxy-Authorization"
).
FirstOrDefault
()
.
Value
.
Trim
();
var
header
=
httpHeaders
.
FirstOrDefault
(
t
=>
t
.
Name
==
"Proxy-Authorization"
);
if
(
null
==
header
)
throw
new
NullReferenceException
();
var
headerValue
=
header
.
Value
.
Trim
();
if
(!
headerValue
.
ToLower
().
StartsWith
(
"basic"
))
{
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
@@ -63,10 +77,17 @@ namespace Titanium.Web.Proxy
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
@@ -76,17 +97,20 @@ namespace Titanium.Web.Proxy
var
password
=
decoded
.
Substring
(
decoded
.
IndexOf
(
':'
)
+
1
);
return
await
AuthenticateUserFunc
(
username
,
password
).
ConfigureAwait
(
false
);
}
}
catch
(
Exception
e
)
{
ExceptionFunc
(
new
ProxyAuthorizationException
(
"Error whilst authorizing request"
,
e
,
httpHeaders
));
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
31edf6dd
...
...
@@ -47,14 +47,16 @@ namespace Titanium.Web.Proxy
/// <summary>
/// A object that creates tcp connection to server
/// </summary>
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
set
;
}
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
}
/// <summary>
/// Manage system proxy settings
/// </summary>
private
SystemProxyManager
systemProxySettingsManager
{
get
;
set
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
#if !DEBUG
private
FireFoxProxySettingsManager
firefoxProxySettingsManager
{
get
;
set
;
}
#endif
/// <summary>
/// Buffer size used throughout this proxy
...
...
@@ -138,14 +140,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public
Action
<
Exception
>
ExceptionFunc
{
get
{
return
exceptionFunc
??
defaultExceptionFunc
.
Value
;
}
set
{
exceptionFunc
=
value
;
}
get
=>
exceptionFunc
??
defaultExceptionFunc
.
Value
;
set
=>
exceptionFunc
=
value
;
}
/// <summary>
...
...
@@ -172,6 +168,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// return the ExternalProxy object with valid credentials
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
{
get
;
...
...
@@ -203,6 +200,11 @@ namespace Titanium.Web.Proxy
/// </summary>
public
ProxyServer
()
:
this
(
null
,
null
)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="rootCertificateName">Name of root certificate.</param>
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
RootCertificateName
=
rootCertificateName
;
...
...
@@ -214,8 +216,9 @@ namespace Titanium.Web.Proxy
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
tcpConnectionFactory
=
new
TcpConnectionFactory
();
systemProxySettingsManager
=
new
SystemProxyManager
();
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
#if !DEBUG
new
FireFoxProxySettingsManager
();
#endif
RootCertificateName
=
RootCertificateName
??
"Titanium Root Certificate Authority"
;
RootCertificateIssuerName
=
RootCertificateIssuerName
??
"Titanium"
;
}
...
...
@@ -277,7 +280,7 @@ namespace Titanium.Web.Proxy
#if !DEBUG
firefoxProxySettingsManager
.
AddFirefox
();
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {
1} and port: {2} as System HTTP Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
Console
.
WriteLine
(
"Set endpoint at Ip {
0} and port: {1} as System HTTP Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
...
...
@@ -313,7 +316,7 @@ namespace Titanium.Web.Proxy
#if !DEBUG
firefoxProxySettingsManager
.
AddFirefox
();
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {
1} and port: {2} as System HTTPS Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
Console
.
WriteLine
(
"Set endpoint at Ip {
0} and port: {1} as System HTTPS Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
/// <summary>
...
...
@@ -461,6 +464,7 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint"></param>
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
if
(
endPoint
==
null
)
throw
new
ArgumentNullException
(
nameof
(
endPoint
));
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
...
...
@@ -542,6 +546,9 @@ namespace Titanium.Web.Proxy
endPoint
.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
/// <summary>
/// Dispose Proxy.
/// </summary>
public
void
Dispose
()
{
if
(
proxyRunning
)
...
...
@@ -551,5 +558,45 @@ namespace Titanium.Web.Proxy
certificateCacheManager
?.
Dispose
();
}
/// <summary>
/// Invocator for BeforeRequest event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnBeforeRequest
(
object
sender
,
SessionEventArgs
e
)
{
BeforeRequest
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for BeforeResponse event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns></returns>
protected
virtual
void
OnBeforeResponse
(
object
sender
,
SessionEventArgs
e
)
{
BeforeResponse
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ServerCertificateValidationCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnServerCertificateValidationCallback
(
object
sender
,
CertificateValidationEventArgs
e
)
{
ServerCertificateValidationCallback
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ClientCertifcateSelectionCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnClientCertificateSelectionCallback
(
object
sender
,
CertificateSelectionEventArgs
e
)
{
ClientCertificateSelectionCallback
?.
Invoke
(
sender
,
e
);
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/RequestHandler.cs
View file @
31edf6dd
...
...
@@ -11,7 +11,6 @@ using Titanium.Web.Proxy.Exceptions;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Cryptography.X509Certificates
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Http
;
using
System.Threading.Tasks
;
...
...
@@ -58,29 +57,21 @@ namespace Titanium.Web.Proxy
//Find the request Verb
var
httpVerb
=
httpCmdSplit
[
0
];
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
{
httpRemoteUri
=
new
Uri
(
"http://"
+
httpCmdSplit
[
1
]);
}
else
{
httpRemoteUri
=
new
Uri
(
httpCmdSplit
[
1
]);
}
httpRemoteUri
=
httpVerb
.
ToUpper
()
==
"CONNECT"
?
new
Uri
(
"http://"
+
httpCmdSplit
[
1
])
:
new
Uri
(
httpCmdSplit
[
1
]);
//parse the HTTP version
Version
version
=
new
Version
(
1
,
1
);
var
version
=
new
Version
(
1
,
1
);
if
(
httpCmdSplit
.
Length
==
3
)
{
string
httpVersion
=
httpCmdSplit
[
2
].
Trim
();
var
httpVersion
=
httpCmdSplit
[
2
].
Trim
();
if
(
httpVersion
==
"http/1.0"
)
if
(
0
==
string
.
CompareOrdinal
(
httpVersion
,
"http/1.0"
)
)
{
version
=
new
Version
(
1
,
0
);
}
}
//filter out excluded host names
var
excluded
=
endPoint
.
ExcludedHttpsHostNameRegex
!=
null
?
endPoint
.
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
:
false
;
var
excluded
=
endPoint
.
ExcludedHttpsHostNameRegex
!=
null
&&
endPoint
.
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
));
List
<
HttpHeader
>
connectRequestHeaders
=
null
;
...
...
@@ -89,7 +80,7 @@ namespace Titanium.Web.Proxy
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
string
tmpLine
=
null
;
string
tmpLine
;
connectRequestHeaders
=
new
List
<
HttpHeader
>();
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
...
...
@@ -114,15 +105,7 @@ namespace Titanium.Web.Proxy
sslStream
=
new
SslStream
(
clientStream
,
true
);
X509Certificate2
certificate
;
if
(
endPoint
.
GenericCertificate
!=
null
)
{
certificate
=
endPoint
.
GenericCertificate
;
}
else
{
certificate
=
certificateCacheManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
}
var
certificate
=
endPoint
.
GenericCertificate
??
certificateCacheManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
//Successfully managed to authenticate the client using the fake certificate
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
...
...
@@ -136,10 +119,7 @@ namespace Titanium.Web.Proxy
}
catch
{
if
(
sslStream
!=
null
)
{
sslStream
.
Dispose
();
}
sslStream
?.
Dispose
();
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
...
...
@@ -160,8 +140,8 @@ namespace Titanium.Web.Proxy
await
TcpHelper
.
SendRaw
(
BUFFER_SIZE
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpCmd
,
version
,
null
,
false
,
SupportedSslProtocols
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
)
,
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
)
,
ValidateServerCertificate
,
SelectClientCertificate
,
clientStream
,
tcpConnectionFactory
,
UpStreamEndPoint
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
...
...
@@ -169,7 +149,7 @@ namespace Titanium.Web.Proxy
}
//Now create the request
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
httpRemoteUri
.
Host
:
null
,
endPoint
,
connectRequestHeaders
,
null
,
null
);
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
httpRemoteUri
.
Host
:
null
,
endPoint
,
connectRequestHeaders
);
}
catch
(
Exception
)
{
...
...
@@ -189,14 +169,13 @@ namespace Titanium.Web.Proxy
CustomBinaryReader
clientStreamReader
=
null
;
StreamWriter
clientStreamWriter
=
null
;
X509Certificate2
certificate
=
null
;
if
(
endPoint
.
EnableSsl
)
{
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
//implement in future once SNI supported by SSL stream, for now use the same certificate
certificate
=
certificateCacheManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
var
certificate
=
certificateCacheManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
try
{
...
...
@@ -259,8 +238,8 @@ namespace Titanium.Web.Proxy
connection
=
await
tcpConnectionFactory
.
CreateClient
(
BUFFER_SIZE
,
ConnectionTimeOutSeconds
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
IsHttps
,
SupportedSslProtocols
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
)
,
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
)
,
ValidateServerCertificate
,
SelectClientCertificate
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
,
args
.
ProxyClient
.
ClientStream
,
UpStreamEndPoint
);
}
...
...
@@ -367,9 +346,14 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="httpsHostName"></param>
/// <param name="endPoint"></param>
/// <param name="connectHeaders"></param>
/// <param name="customUpStreamHttpProxy"></param>
/// <param name="customUpStreamHttpsProxy"></param>
/// <returns></returns>
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
,
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
,
ExternalProxy
customUpStreamHttpProxy
=
null
,
ExternalProxy
customUpStreamHttpsProxy
=
null
)
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
,
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
,
ExternalProxy
customUpStreamHttpProxy
=
null
,
ExternalProxy
customUpStreamHttpsProxy
=
null
)
{
TcpConnection
connection
=
null
;
...
...
@@ -383,9 +367,12 @@ namespace Titanium.Web.Proxy
break
;
}
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
,
HandleHttpSessionResponse
);
args
.
ProxyClient
.
TcpClient
=
client
;
args
.
WebSession
.
ConnectHeaders
=
connectHeaders
;
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
,
HandleHttpSessionResponse
)
{
ProxyClient
=
{
TcpClient
=
client
},
WebSession
=
{
ConnectHeaders
=
connectHeaders
}
};
args
.
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
{
...
...
@@ -409,12 +396,12 @@ namespace Titanium.Web.Proxy
var
httpMethod
=
httpCmdSplit
[
0
];
//find the request HTTP version
Version
httpVersion
=
new
Version
(
1
,
1
);
var
httpVersion
=
new
Version
(
1
,
1
);
if
(
httpCmdSplit
.
Length
==
3
)
{
var
httpVersionString
=
httpCmdSplit
[
2
].
ToLower
().
Trim
();
if
(
httpVersionString
==
"http/1.0"
)
if
(
0
==
string
.
CompareOrdinal
(
httpVersionString
,
"http/1.0"
)
)
{
httpVersion
=
new
Version
(
1
,
0
);
}
...
...
@@ -439,10 +426,8 @@ namespace Titanium.Web.Proxy
{
var
existing
=
args
.
WebSession
.
Request
.
RequestHeaders
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
()
;
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
}
;
nonUniqueHeaders
.
Add
(
existing
);
nonUniqueHeaders
.
Add
(
newHeader
);
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Remove
(
newHeader
.
Name
);
...
...
@@ -455,8 +440,7 @@ namespace Titanium.Web.Proxy
}
var
httpRemoteUri
=
new
Uri
(
httpsHostName
==
null
?
httpCmdSplit
[
1
]
:
(
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
==
null
?
httpsHostName
:
args
.
WebSession
.
Request
.
Host
,
httpCmdSplit
[
1
])));
:
(
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
??
httpsHostName
,
httpCmdSplit
[
1
])));
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
...
...
@@ -479,10 +463,10 @@ namespace Titanium.Web.Proxy
//If user requested interception do it
if
(
BeforeRequest
!=
null
)
{
Delegate
[]
invocationList
=
BeforeRequest
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
var
invocationList
=
BeforeRequest
.
GetInvocationList
();
var
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
for
(
var
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
...
...
@@ -495,8 +479,8 @@ namespace Titanium.Web.Proxy
{
await
TcpHelper
.
SendRaw
(
BUFFER_SIZE
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpCmd
,
httpVersion
,
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
IsHttps
,
SupportedSslProtocols
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
)
,
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
)
,
SupportedSslProtocols
,
ValidateServerCertificate
,
SelectClientCertificate
,
clientStream
,
tcpConnectionFactory
,
UpStreamEndPoint
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
...
...
@@ -504,7 +488,7 @@ namespace Titanium.Web.Proxy
}
//construct the web request that we are going to issue on behalf of the client.
await
HandleHttpSessionRequestInternal
(
connection
,
args
,
customUpStreamHttpProxy
,
customUpStreamHttpsProxy
,
false
).
ConfigureAwait
(
false
);
await
HandleHttpSessionRequestInternal
(
null
,
args
,
customUpStreamHttpProxy
,
customUpStreamHttpsProxy
,
false
).
ConfigureAwait
(
false
);
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
...
...
@@ -531,12 +515,8 @@ namespace Titanium.Web.Proxy
}
if
(
connection
!=
null
)
{
//dispose
connection
.
Dispose
();
}
connection
?.
Dispose
();
}
/// <summary>
...
...
@@ -547,8 +527,9 @@ namespace Titanium.Web.Proxy
/// <returns></returns>
private
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
{
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2}"
,
httpVersion
.
Major
,
httpVersion
.
Minor
,
"200 Connection established"
));
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
));
await
clientStreamWriter
.
WriteLineAsync
(
$"HTTP/
{
httpVersion
.
Major
}
.
{
httpVersion
.
Minor
}
200 Connection established"
);
await
clientStreamWriter
.
WriteLineAsync
(
$"Timestamp:
{
DateTime
.
Now
}
"
);
await
clientStreamWriter
.
WriteLineAsync
();
await
clientStreamWriter
.
FlushAsync
();
}
...
...
@@ -570,9 +551,6 @@ namespace Titanium.Web.Proxy
case
"accept-encoding"
:
header
.
Value
=
"gzip,deflate"
;
break
;
default
:
break
;
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
31edf6dd
...
...
@@ -17,7 +17,11 @@ namespace Titanium.Web.Proxy
/// </summary>
partial
class
ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
/// <summary>
/// Called asynchronously when a request was successfully and we received the response
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
//read response & headers from server
...
...
@@ -156,14 +160,14 @@ namespace Titanium.Web.Proxy
private
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
StreamWriter
responseWriter
)
{
await
responseWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
code
,
description
)
);
await
responseWriter
.
WriteLineAsync
(
$"HTTP/
{
version
.
Major
}
.
{
version
.
Minor
}
{
code
}
{
description
}
"
);
}
/// <summary>
/// Write response headers to client
/// </summary>
/// <param name="responseWriter"></param>
/// <param name="
headers
"></param>
/// <param name="
response
"></param>
/// <returns></returns>
private
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
Response
response
)
{
...
...
@@ -220,7 +224,6 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Handle dispose of a client/server session
/// </summary>
/// <param name="tcpClient"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
...
...
@@ -235,21 +238,13 @@ namespace Titanium.Web.Proxy
clientStream
.
Dispose
();
}
if
(
args
!=
null
)
{
args
.
Dispose
();
}
args
?.
Dispose
();
if
(
clientStreamReader
!=
null
)
{
clientStreamReader
.
Dispose
();
}
clientStreamReader
?.
Dispose
();
if
(
clientStreamWriter
!=
null
)
{
if
(
clientStreamWriter
==
null
)
return
;
clientStreamWriter
.
Close
();
clientStreamWriter
.
Dispose
();
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
31edf6dd
using
System
;
using
System.Text
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Shared
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment