Skip to content

Commit

Permalink
feat: adds BouncyCertificate
Browse files Browse the repository at this point in the history
  • Loading branch information
ndorin committed Nov 8, 2023
1 parent a82e53c commit 072d77a
Show file tree
Hide file tree
Showing 3 changed files with 492 additions and 52 deletions.
183 changes: 131 additions & 52 deletions src/Pepperdash Core/Logging/DebugWebsocketSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,43 @@
using Serilog.Configuration;
using WebSocketSharp.Server;
using Crestron.SimplSharp;
using System.Net.Http;
using System.Text.RegularExpressions;
using WebSocketSharp;
using System.Security.Authentication;
using WebSocketSharp.Net;
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
using System.IO;
using Org.BouncyCastle.Asn1.X509;

namespace PepperDash.Core
{
public class DebugWebsocketSink : ILogEventSink
{
private HttpServer _server;

private HttpServer _httpsServer;
private string _path = "/join";
private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345";

public int Port
{ get
{

if(_server == null) return 0;
return _server.Port;
if(_httpsServer == null) return 0;
return _httpsServer.Port;
}
}

public bool IsListening
{ get
{
if (_server == null) return false;
return _server.IsListening;
}
}
public bool IsRunning { get => _httpsServer?.IsListening ?? false; }


private readonly IFormatProvider _formatProvider;

public DebugWebsocketSink()
{

if (!File.Exists($"\\user\\{_certificateName}.pfx"))
CreateCert(null);

CrestronEnvironment.ProgramStatusEventHandler += type =>
{
if (type == eProgramStatusEventType.Stopping)
Expand All @@ -51,26 +55,133 @@ public DebugWebsocketSink()
};
}

private void CreateCert(string[] args)
{
try
{
Debug.Console(0,$"CreateCert Creating Utility");
//var utility = new CertificateUtility();
var utility = new BouncyCertificate();
Debug.Console(0, $"CreateCert Calling CreateCert");
//utility.CreateCert();
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);

Debug.Console(0, $"DomainName: {domainName} | HostName: {hostName} | {hostName}.{domainName}@{ipAddress}");

var certificate = utility.CreateSelfSignedCertificate($"CN={hostName}.{domainName}", new[] { $"{hostName}.{domainName}", ipAddress }, new[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth });
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
//Debug.Print($"CreateCert Storing Certificate To My.LocalMachine");
//utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine);
Debug.Console(0, $"CreateCert Saving Cert to \\user\\");
utility.CertificatePassword = _certificatePassword;
utility.WriteCertificate(certificate, @"\user\", _certificateName);
Debug.Console(0, $"CreateCert Ending CreateCert");
}
catch (Exception ex)
{
Debug.Console(0, $"WSS CreateCert Failed\r\n{ex.Message}\r\n{ex.StackTrace}");
}
}

public void Emit(LogEvent logEvent)
{
if (_server == null || !_server.IsListening) return;
if (_httpsServer == null || !_httpsServer.IsListening) return;

var message = logEvent.RenderMessage(_formatProvider);
_server.WebSocketServices.Broadcast(message);
_httpsServer.WebSocketServices.Broadcast(message);
}

public void StartServerAndSetPort(int port)
{
Debug.Console(0, "Starting Websocket Server on port: {0}", port);
_server = new HttpServer(port);
_server.AddWebSocketService<DebugClient>(_path);
_server.Start();


Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword, @"\html\wss");
}

private void Start(int port, string certPath = "", string certPassword = "", string rootPath = @"\html")
{
try
{
_httpsServer = new HttpServer(port, true)
{
RootPath = rootPath
};

if (!string.IsNullOrWhiteSpace(certPath))
{
Debug.Console(0, "Assigning SSL Configuration");
_httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword))
{
ClientCertificateRequired = false,
CheckCertificateRevocation = false,
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
//this is just to test, you might want to actually validate
ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
return true;
}
};
}
Debug.Console(0, "Adding Debug Client Service");
_httpsServer.AddWebSocketService<DebugClient>("/echo");
Debug.Console(0, "Assigning Log Info");
_httpsServer.Log.Level = LogLevel.Trace;
_httpsServer.Log.Output = delegate
{
//Debug.Print(DebugLevel.WebSocket, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s);
};
Debug.Console(0, "Starting");

//_httpsServer.OnGet += (sender, e) =>
//{
// Debug.Console(0, $"OnGet requesting {e.Request}");
// var req = e.Request;
// var res = e.Response;

// var path = req.RawUrl;

// if (path == "/")
// path += "index.html";

// var localPath = Path.Combine(rootPath, path.Substring(1));

// byte[] contents;
// if (File.Exists(localPath))
// contents = File.ReadAllBytes(localPath);
// else
// {
// e.Response.StatusCode = 404;
// contents = Encoding.UTF8.GetBytes("Path not found " + e.Request.RawUrl);
// }

// var extention = Path.GetExtension(path);
// if (!_contentTypes.TryGetValue(extention, out var contentType))
// contentType = "text/html";

// res.ContentLength64 = contents.LongLength;

// res.Close(contents, true);
//};

_httpsServer.Start();
Debug.Console(0, "Ready");
}
catch (Exception ex)
{
Debug.Console(0, "WebSocket Failed to start {0}", ex.Message);
}
}

public void StopServer()
{
Debug.Console(0, "Stopping Websocket Server");
_server.Stop();
_httpsServer?.Stop();

_httpsServer = null;
}
}

Expand Down Expand Up @@ -115,39 +226,7 @@ protected override void OnOpen()
var url = Context.WebSocket.Url;
Debug.Console(2, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);

//var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");

//if (match.Success)
//{
// var clientId = match.Groups[1].Value;

// // Inform controller of client joining
// if (Controller != null)
// {
// var clientJoined = new MobileControlResponseMessage
// {
// Type = "/system/roomKey",
// ClientId = clientId,
// Content = RoomKey,
// };

// Controller.SendMessageObjectToDirectClient(clientJoined);

// var bridge = Controller.GetRoomBridge(RoomKey);

// SendUserCodeToClient(bridge, clientId);

// bridge.UserCodeChanged += (sender, args) => SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, clientId);
// }
// else
// {
// Debug.Console(2, "WebSocket UiClient Controller is null");
// }
//}

_connectionTime = DateTime.Now;

// TODO: Future: Check token to see if there's already an open session using that token and reject/close the session
}

protected override void OnMessage(MessageEventArgs e)
Expand All @@ -165,7 +244,7 @@ protected override void OnClose(CloseEventArgs e)

}

protected override void OnError(ErrorEventArgs e)
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
base.OnError(e);

Expand Down
1 change: 1 addition & 0 deletions src/Pepperdash Core/PepperDash_Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle" Version="1.8.9" />
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.19.35" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2">
<Aliases>Full</Aliases>
Expand Down
Loading

0 comments on commit 072d77a

Please sign in to comment.