using System.Security.Cryptography.X509Certificates; using Microsoft.Extensions.Options; using StellaOps.Zastava.Webhook.Configuration; namespace StellaOps.Zastava.Webhook.Certificates; public interface IWebhookCertificateProvider { X509Certificate2 GetCertificate(); } public sealed class WebhookCertificateProvider : IWebhookCertificateProvider { private readonly ILogger _logger; private readonly ZastavaWebhookTlsOptions _options; private readonly Lazy _certificate; private readonly IWebhookCertificateSource _certificateSource; public WebhookCertificateProvider( IOptions options, IEnumerable certificateSources, ILogger logger) { _logger = logger; _options = options.Value.Tls; _certificateSource = certificateSources.FirstOrDefault(source => source.CanHandle(_options.Mode)) ?? throw new InvalidOperationException($"No certificate source registered for mode {_options.Mode}."); _certificate = new Lazy(LoadCertificate, LazyThreadSafetyMode.ExecutionAndPublication); } public X509Certificate2 GetCertificate() => _certificate.Value; private X509Certificate2 LoadCertificate() { _logger.LogInformation("Loading webhook TLS certificate using {Mode} mode.", _options.Mode); var certificate = _certificateSource.LoadCertificate(_options); _logger.LogInformation("Loaded webhook TLS certificate with subject {Subject} and thumbprint {Thumbprint}.", certificate.Subject, certificate.Thumbprint); return certificate; } } public interface IWebhookCertificateSource { bool CanHandle(ZastavaWebhookTlsMode mode); X509Certificate2 LoadCertificate(ZastavaWebhookTlsOptions options); }