feat: add HTTP GET handler to RoutingFeedbackWebSocket for client certificate confirmation

This commit is contained in:
Neil Dorin 2026-06-22 22:48:16 -06:00
parent b65f895e06
commit a1d168c4ed
2 changed files with 41 additions and 21 deletions

View file

@ -50,11 +50,11 @@ public static class Extensions
/// </summary> /// </summary>
private static Dictionary<string, List<TieLine>> _tieLinesBySource; private static Dictionary<string, List<TieLine>> _tieLinesBySource;
/// <summary> // /// <summary>
/// Cache of failed route attempts to avoid re-checking impossible paths. // /// Cache of failed route attempts to avoid re-checking impossible paths.
/// Format: "sourceKey|destKey|signalType" // /// Format: "sourceKey|destKey|signalType"
/// </summary> // /// </summary>
private static readonly HashSet<string> _impossibleRoutes = new HashSet<string>(); // private static readonly HashSet<string> _impossibleRoutes = new HashSet<string>();
/// <summary> /// <summary>
/// Indexes all TieLines by source and destination device keys for faster lookups. /// Indexes all TieLines by source and destination device keys for faster lookups.
@ -130,14 +130,14 @@ public static class Extensions
return string.Format("{0}|{1}|{2}", sourceKey, destKey, type); return string.Format("{0}|{1}|{2}", sourceKey, destKey, type);
} }
/// <summary> // /// <summary>
/// Clears the impossible routes cache. Should be called if TieLines are added/removed at runtime. // /// Clears the impossible routes cache. Should be called if TieLines are added/removed at runtime.
/// </summary> // /// </summary>
public static void ClearImpossibleRoutesCache() // public static void ClearImpossibleRoutesCache()
{ // {
_impossibleRoutes.Clear(); // _impossibleRoutes.Clear();
Debug.LogMessage(LogEventLevel.Information, "Impossible routes cache cleared"); // Debug.LogMessage(LogEventLevel.Information, "Impossible routes cache cleared");
} // }
/// <summary> /// <summary>
@ -549,12 +549,12 @@ public static class Extensions
{ {
cycle++; cycle++;
var routeKey = GetRouteKey(source.Key, destination.Key, signalType); // var routeKey = GetRouteKey(source.Key, destination.Key, signalType);
if (_impossibleRoutes.Contains(routeKey)) // if (_impossibleRoutes.Contains(routeKey))
{ // {
Debug.LogMessage(LogEventLevel.Verbose, "Route {0} is cached as impossible, skipping", null, routeKey); // Debug.LogMessage(LogEventLevel.Verbose, "Route {0} is cached as impossible, skipping", null, routeKey);
return false; // return false;
} // }
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString()); Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString());
@ -651,8 +651,8 @@ public static class Extensions
{ {
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key);
// Cache this as an impossible route // // Cache this as an impossible route
_impossibleRoutes.Add(routeKey); // _impossibleRoutes.Add(routeKey);
return false; return false;
} }

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Timers; using System.Timers;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -11,6 +12,7 @@ using Newtonsoft.Json.Serialization;
using PepperDash.Core; using PepperDash.Core;
using Serilog.Events; using Serilog.Events;
using WebSocketSharp; using WebSocketSharp;
using WebSocketSharp.Net;
using WebSocketSharp.Server; using WebSocketSharp.Server;
namespace PepperDash.Essentials.Core.Web; namespace PepperDash.Essentials.Core.Web;
@ -113,6 +115,7 @@ public class RoutingFeedbackWebsocket : IKeyed
_httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; _httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
_httpsServer.AddWebSocketService<RoutingFeedbackClient>(_path, () => new RoutingFeedbackClient(this)); _httpsServer.AddWebSocketService<RoutingFeedbackClient>(_path, () => new RoutingFeedbackClient(this));
_httpsServer.OnGet += HandleHttpGet;
_httpsServer.Log.Level = LogLevel.Warn; _httpsServer.Log.Level = LogLevel.Warn;
_httpsServer.Start(); _httpsServer.Start();
@ -337,6 +340,23 @@ public class RoutingFeedbackWebsocket : IKeyed
service.Sessions.Broadcast(message); service.Sessions.Broadcast(message);
} }
private void HandleHttpGet(object sender, HttpRequestEventArgs e)
{
var res = e.Response;
res.ContentType = "text/html";
res.ContentEncoding = Encoding.UTF8;
res.StatusCode = 200;
const string html = @"<!DOCTYPE html>
<html><head><title>Essentials Routing Feedback</title></head>
<body style=""font-family:sans-serif;padding:2rem;text-align:center"">
<h2>Certificate Accepted</h2>
<p>You may close this tab and return to the configuration app.</p>
</body></html>";
res.WriteContent(Encoding.UTF8.GetBytes(html));
}
private static X509Certificate2 LoadCert(string certPath, string certPassword) private static X509Certificate2 LoadCert(string certPath, string certPassword)
{ {
return new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.EphemeralKeySet); return new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.EphemeralKeySet);