diff --git a/EonaCat.Network/System/Sockets/Web/WebSocketSecureClient.cs b/EonaCat.Network/System/Sockets/Web/WebSocketSecureClient.cs
index c90eb5d..2d4688f 100644
--- a/EonaCat.Network/System/Sockets/Web/WebSocketSecureClient.cs
+++ b/EonaCat.Network/System/Sockets/Web/WebSocketSecureClient.cs
@@ -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
///
/// The client certificate for the connection
/// The password for the connection
+ /// The keepalive interval in seconds for the connection
+ /// The cookies to be send with the connection
///
- 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);
diff --git a/EonaCat.Network/System/Sockets/Web/WebSocketSecureServer.cs b/EonaCat.Network/System/Sockets/Web/WebSocketSecureServer.cs
index 6f5351d..e9c8229 100644
--- a/EonaCat.Network/System/Sockets/Web/WebSocketSecureServer.cs
+++ b/EonaCat.Network/System/Sockets/Web/WebSocketSecureServer.cs
@@ -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
///
public event Action OnDisconnect;
+ ///
+ /// The TLS version to be used by the server
+ ///
+ public SslProtocols TlsVersion { get; set; } = SslProtocols.Tls12;
+
///
/// OnError event
///
@@ -48,6 +54,9 @@ namespace EonaCat.Network
private readonly Dictionary _connectedClients = new Dictionary();
private readonly Dictionary _clientNames = new Dictionary();
+ public CookieContainer Cookies { get; private set; } = new CookieContainer();
+ public bool IsDebugHttpConnection { get; set; }
+
///
/// Create secure WebSocket server with certificate support
///
@@ -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) { }
}
}
+
+ ///
+ /// Debug the HTTPS connection information
+ ///
+ /// HttpListenerContext representing the incoming connection
+ 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}");
+ }
+ }
}
}
diff --git a/EonaCat.Network/System/Sockets/Web/WebSocketTransportContext.cs b/EonaCat.Network/System/Sockets/Web/WebSocketTransportContext.cs
new file mode 100644
index 0000000..484d7a3
--- /dev/null
+++ b/EonaCat.Network/System/Sockets/Web/WebSocketTransportContext.cs
@@ -0,0 +1,9 @@
+using System.Security.Authentication;
+
+namespace EonaCat.Network
+{
+ public class WebSocketTransportContext
+ {
+ public SslProtocols TlsVersion { get; set; }
+ }
+}
diff --git a/EonaCat.Network/System/Tools/CertificateInfoHelper.cs b/EonaCat.Network/System/Tools/CertificateInfoHelper.cs
new file mode 100644
index 0000000..a1d5d48
--- /dev/null
+++ b/EonaCat.Network/System/Tools/CertificateInfoHelper.cs
@@ -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 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}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Tools/Helpers.cs b/EonaCat.Network/System/Tools/Helpers.cs
index c091144..f182cc7 100644
--- a/EonaCat.Network/System/Tools/Helpers.cs
+++ b/EonaCat.Network/System/Tools/Helpers.cs
@@ -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;