using GenHTTP.Api.Content; using GenHTTP.Api.Infrastructure; using GenHTTP.Api.Protocol; using GenHTTP.Engine; using GenHTTP.Modules.Practices; using InABox.API; using InABox.Core; using NPOI.SS.Formula.Functions; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using System.Timers; using Timer = System.Timers.Timer; namespace PRSServices; public abstract class Handler : IHandler { public IHandler Parent { get; set; } public abstract void Init(TProperties properties); public abstract ValueTask HandleAsync(IRequest request); public ValueTask PrepareAsync() { return new ValueTask(); } public IEnumerable GetContent(IRequest request) { return Enumerable.Empty(); } } public class HandlerBuilder : IHandlerBuilder> where THandler : Handler, new() { private readonly List _Concerns = new(); public HandlerBuilder(TProperties properties) { Properties = properties; } private TProperties Properties; public HandlerBuilder Add(IConcernBuilder concern) { _Concerns.Add(concern); return this; } public IHandler Build(IHandler parent) { return Concerns.Chain(parent, _Concerns, p => { var handler = new THandler { Parent = p }; handler.Init(Properties); return handler; }); } } public class Listener where THandler : Handler, new() where TProperties : notnull { private CertificateManager CertificateManager; private ushort Port; private IServerHost host; private TProperties Properties; public Listener(TProperties properties) { CertificateManager = new CertificateManager(); CertificateManager.UpdateCertificate += CertificateManager_UpdateCertificate; CertificateManager.CertificateExpiring += CertificateManager_CertificateExpiring; CertificateManager.CertificateExpired += CertificateManager_CertificateExpired; Init(properties); } private void CertificateManager_CertificateExpired() { Logger.Send(LogType.Information, "", "Expiry of certificate reached; restarting HTTPS listener..."); Restart(); } private void CertificateManager_CertificateExpiring(DateTime expiry) { string message; if (expiry.Date == DateTime.Now.Date) { message = $"HTTPS Certificate will expire today at {expiry.TimeOfDay:hh\\:mm}"; } else { message = $"HTTPS Certificate will expire in {(expiry - DateTime.Now).Days} at {expiry:dd/MM/yyyy hh:mm}"; } Logger.Send(LogType.Information, "", message); } private void CertificateManager_UpdateCertificate(X509Certificate2 certificate) { Logger.Send(LogType.Information, "", "HTTPS Certificate with greater expiry date found; restarting HTTPS listener..."); Restart(); } [MemberNotNull("host", "Properties")] public void Init(TProperties properties) { Properties = properties; host = Host.Create() .Console() .Handler(new HandlerBuilder(properties)) .Defaults(); } private void InitCertificate(ushort port, X509Certificate2 certificate) { host.Bind(IPAddress.Any, port, certificate); } public void InitPort(ushort port) { Port = port; host.Bind(IPAddress.Any, port); } public void InitHTTPS(ushort port, string certificateFile) { Port = port; CertificateManager.SetFile(certificateFile); var status = CertificateManager.GetCertificate(out var certificate); switch (status) { case CertificateStatus.Valid: var names = certificate!.GetNameInfo(X509NameType.DnsName, false); Logger.Send(LogType.Information, "", $"Certificate valid for {names}"); InitCertificate(port, certificate); break; case CertificateStatus.Expired: Logger.Send(LogType.Error, "", "HTTPS Certificate has expired, using HTTP instead"); InitPort(port); break; case CertificateStatus.NotFound: InitPort(port); break; case CertificateStatus.Error: Logger.Send(LogType.Error, "", "Error validating HTTPS Certificate, using HTTP instead"); InitPort(port); break; } } public void Start() { host.Start(); } public void Stop() { host.Stop(); CertificateManager.Stop(); } private void Restart() { Clear(); Init(Properties); if(CertificateManager.CertificateFile != null) { InitHTTPS(Port, CertificateManager.CertificateFile); } else { InitPort(Port); } Start(); } /// /// Clears certificate and host information, and stops the listener. /// private void Clear() { host?.Stop(); CertificateManager.Clear(); } }