Updated
This commit is contained in:
parent
d6f0c7b5af
commit
89cb9df95b
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
@ -44,13 +45,15 @@ namespace EonaCat.Network
|
|||
/// <param name="uri"></param>
|
||||
/// <param name="clientCertificate">The client certificate for the connection</param>
|
||||
/// <param name="password">The password for the connection</param>
|
||||
/// <param name="keepAliveIntervalSeconds">The keepalive interval in seconds for the connection</param>
|
||||
/// <param name="cookieContainer">The cookies to be send with the connection</param>
|
||||
/// <returns></returns>
|
||||
public Task ConnectAsync(string uri, X509Certificate2 clientCertificate = null, string password = null)
|
||||
public Task ConnectAsync(string uri, X509Certificate2 clientCertificate = null, string password = null, int keepAliveIntervalSeconds = 30, CookieContainer? cookieContainer = null)
|
||||
{
|
||||
return CreateWebSocketClientAsync(uri, clientCertificate, password);
|
||||
return CreateWebSocketClientAsync(uri, clientCertificate, password, keepAliveIntervalSeconds, cookieContainer);
|
||||
}
|
||||
|
||||
private async Task CreateWebSocketClientAsync(string uri, X509Certificate2 clientCertificate, string password)
|
||||
private async Task CreateWebSocketClientAsync(string uri, X509Certificate2 clientCertificate, string password, int keepAliveIntervalSeconds = 30, CookieContainer? cookieContainer = null)
|
||||
{
|
||||
_webSocket = new ClientWebSocket();
|
||||
|
||||
|
@ -70,6 +73,17 @@ namespace EonaCat.Network
|
|||
_webSocket.Options.SetRequestHeader("ClientName", ClientName);
|
||||
}
|
||||
|
||||
if (cookieContainer != null && cookieContainer.Count > 0)
|
||||
{
|
||||
// Manually set cookies in the request header
|
||||
_webSocket.Options.SetRequestHeader("Cookie", cookieContainer.GetCookieHeader(new Uri(uri)));
|
||||
}
|
||||
|
||||
if (keepAliveIntervalSeconds > 0)
|
||||
{
|
||||
_webSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(keepAliveIntervalSeconds);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Uri serverUri = new Uri(uri);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -33,6 +34,11 @@ namespace EonaCat.Network
|
|||
/// </summary>
|
||||
public event Action<RemoteInfo> OnDisconnect;
|
||||
|
||||
/// <summary>
|
||||
/// The TLS version to be used by the server
|
||||
/// </summary>
|
||||
public SslProtocols TlsVersion { get; set; } = SslProtocols.Tls12;
|
||||
|
||||
/// <summary>
|
||||
/// OnError event
|
||||
/// </summary>
|
||||
|
@ -48,6 +54,9 @@ namespace EonaCat.Network
|
|||
private readonly Dictionary<string, WebSocket> _connectedClients = new Dictionary<string, WebSocket>();
|
||||
private readonly Dictionary<string, string> _clientNames = new Dictionary<string, string>();
|
||||
|
||||
public CookieContainer Cookies { get; private set; } = new CookieContainer();
|
||||
public bool IsDebugHttpConnection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create secure WebSocket server with certificate support
|
||||
/// </summary>
|
||||
|
@ -63,7 +72,18 @@ namespace EonaCat.Network
|
|||
|
||||
foreach (var uriPrefix in uriPrefixes)
|
||||
{
|
||||
_listener.Prefixes.Add(uriPrefix);
|
||||
if (uriPrefix.StartsWith("https"))
|
||||
{
|
||||
_listener.Prefixes.Add(uriPrefix);
|
||||
}
|
||||
else if (uriPrefix.StartsWith("wss"))
|
||||
{
|
||||
_listener.Prefixes.Add(uriPrefix.Replace("wss", "https"));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid URI prefix. Use 'https' or 'wss' prefixes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +108,12 @@ namespace EonaCat.Network
|
|||
{
|
||||
var context = await _listener.GetContextAsync().ConfigureAwait(false);
|
||||
|
||||
if (IsDebugHttpConnection)
|
||||
{
|
||||
// Debug connection
|
||||
DebugHttpsConnection(context);
|
||||
}
|
||||
|
||||
if (context.Request.IsWebSocketRequest)
|
||||
{
|
||||
if (_passwordProtectionEnabled)
|
||||
|
@ -102,6 +128,12 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
// Manually set cookies in the HTTP response header
|
||||
if (Cookies.Count > 0)
|
||||
{
|
||||
context.Response.Headers.Add("Set-Cookie", Cookies.GetCookieHeader(context.Request.Url));
|
||||
}
|
||||
|
||||
string clientName = null;
|
||||
foreach (var key in context.Request.Headers.AllKeys)
|
||||
{
|
||||
|
@ -128,6 +160,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task HandleWebSocketConnectionAsync(WebSocket webSocket, string clientName, CancellationToken cancellationToken)
|
||||
{
|
||||
string clientId = Guid.NewGuid().ToString();
|
||||
|
@ -186,5 +219,62 @@ namespace EonaCat.Network
|
|||
catch (AggregateException) { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug the HTTPS connection information
|
||||
/// </summary>
|
||||
/// <param name="context">HttpListenerContext representing the incoming connection</param>
|
||||
private void DebugHttpsConnection(HttpListenerContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Incoming HTTPS Connection from: {context.Request.RemoteEndPoint}");
|
||||
|
||||
// Output headers
|
||||
Console.WriteLine("Headers:");
|
||||
foreach (string key in context.Request.Headers.Keys)
|
||||
{
|
||||
Console.WriteLine($"{key}: {context.Request.Headers[key]}");
|
||||
}
|
||||
|
||||
// Check if the connection is WebSocket request
|
||||
if (context.Request.IsWebSocketRequest)
|
||||
{
|
||||
Console.WriteLine("WebSocket Request detected.");
|
||||
|
||||
// Output WebSocket-specific information
|
||||
if (_passwordProtectionEnabled)
|
||||
{
|
||||
var password = context.Request.Headers["Password"];
|
||||
Console.WriteLine($"Password: {password}");
|
||||
}
|
||||
|
||||
if (Cookies.Count > 0)
|
||||
{
|
||||
Console.WriteLine($"Cookies: {Cookies.GetCookieHeader(context.Request.Url)}");
|
||||
}
|
||||
|
||||
foreach (var key in context.Request.Headers.AllKeys)
|
||||
{
|
||||
if (key == "ClientName")
|
||||
{
|
||||
var clientName = context.Request.Headers["ClientName"];
|
||||
Console.WriteLine($"ClientName: {clientName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid WebSocket Request. Closing connection.");
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error while debugging HTTPS connection: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using System.Security.Authentication;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public class WebSocketTransportContext
|
||||
{
|
||||
public SslProtocols TlsVersion { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public class CertificateInfoHelper
|
||||
{
|
||||
public static string GetCertificatesInformation(IEnumerable<X509Certificate2> certificates)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
foreach (var certificate in certificates)
|
||||
{
|
||||
if (certificate != null)
|
||||
{
|
||||
stringBuilder.AppendLine(GetCertificateInformation(certificate));
|
||||
}
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public static string GetCertificateInformation(X509Certificate2 certificate)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.AppendLine("Certificate Information:");
|
||||
stringBuilder.AppendLine($"Subject: {certificate.Subject}");
|
||||
stringBuilder.AppendLine($"Issuer: {certificate.Issuer}");
|
||||
stringBuilder.AppendLine($"Serial Number: {certificate.SerialNumber}");
|
||||
stringBuilder.AppendLine($"Thumbprint: {certificate.Thumbprint}");
|
||||
stringBuilder.AppendLine($"Valid From: {certificate.NotBefore}");
|
||||
stringBuilder.AppendLine($"Valid Until: {certificate.NotAfter}");
|
||||
stringBuilder.AppendLine($"Has Private Key: {certificate.HasPrivateKey}");
|
||||
stringBuilder.AppendLine();
|
||||
|
||||
stringBuilder.AppendLine("Public Key Information:");
|
||||
stringBuilder.AppendLine($"Algorithm: {certificate.PublicKey.Key.KeyExchangeAlgorithm}");
|
||||
stringBuilder.AppendLine($"Key Size: {certificate.PublicKey.Key.KeySize}");
|
||||
stringBuilder.AppendLine();
|
||||
|
||||
stringBuilder.AppendLine("Certificate Extensions:");
|
||||
foreach (X509Extension extension in certificate.Extensions)
|
||||
{
|
||||
stringBuilder.AppendLine($" {extension.Oid.FriendlyName}: {extension.Format(true)}");
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public static string GetSubject(X509Certificate2 certificate)
|
||||
{
|
||||
return certificate.Subject;
|
||||
}
|
||||
|
||||
public static string GetIssuer(X509Certificate2 certificate)
|
||||
{
|
||||
return certificate.Issuer;
|
||||
}
|
||||
|
||||
public static string GetValidityPeriod(X509Certificate2 certificate)
|
||||
{
|
||||
return $"Valid From: {certificate.NotBefore}, Valid Until: {certificate.NotAfter}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
|
|
Loading…
Reference in New Issue