torrust-actix 4.2.3

A rich, fast and efficient Bittorrent Tracker.
use crate::ssl::enums::certificate_error::CertificateError;
use crate::ssl::enums::server_identifier::ServerIdentifier;
use crate::ssl::structs::certificate_bundle::CertificateBundle;
use crate::ssl::structs::certificate_store::CertificateStore;
use crate::ssl::structs::dynamic_certificate_resolver::DynamicCertificateResolver;
use rustls::server::ResolvesServerCert;
use std::sync::Arc;

impl std::fmt::Debug for DynamicCertificateResolver {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("DynamicCertificateResolver")
            .field("server_id", &self.server_id)
            .field("has_cached_key", &self.cached_key.read().is_some())
            .finish()
    }
}

impl DynamicCertificateResolver {
    pub fn new(
        store: Arc<CertificateStore>,
        server_id: ServerIdentifier,
    ) -> Result<Self, CertificateError> {
        let resolver = Self {
            store,
            server_id,
            cached_key: parking_lot::RwLock::new(None),
        };
        resolver.refresh_cache()?;
        Ok(resolver)
    }

    pub fn server_id(&self) -> &ServerIdentifier {
        &self.server_id
    }

    pub fn refresh_cache(&self) -> Result<(), CertificateError> {
        let bundle = self
            .store
            .get_certificate(&self.server_id)
            .ok_or_else(|| CertificateError::ServerNotFound(self.server_id.to_string()))?;
        let certified_key = Self::bundle_to_certified_key(&bundle)?;
        *self.cached_key.write() = Some(Arc::new(certified_key));
        log::info!(
            "[CERTIFICATE] Refreshed certificate cache for {}",
            self.server_id
        );
        Ok(())
    }

    pub fn has_certificate(&self) -> bool {
        self.cached_key.read().is_some()
    }

    fn bundle_to_certified_key(bundle: &Arc<CertificateBundle>) -> Result<rustls::sign::CertifiedKey, CertificateError> {
        let signing_key = rustls::crypto::ring::sign::any_supported_type(&bundle.key)
            .map_err(|e| CertificateError::CertifiedKeyError(format!("{e}")))?;
        Ok(rustls::sign::CertifiedKey::new(bundle.certs.clone(), signing_key))
    }
}

impl ResolvesServerCert for DynamicCertificateResolver {
    fn resolve(&self, _client_hello: rustls::server::ClientHello<'_>) -> Option<Arc<rustls::sign::CertifiedKey>> {
        self.cached_key.read().clone()
    }
}