use std::sync::Arc; use anyhow::Result; use chrono::{NaiveDate, Utc}; use rustls::sign::CertifiedKey; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CertSer { pub hostname: String, pub date: NaiveDate, pub valid_days: i64, pub key_pem: String, pub cert_pem: String, } pub struct Cert { pub ser: CertSer, pub certkey: Arc, } impl Cert { pub fn new(ser: CertSer) -> Result { let pem_certs = rustls_pemfile::read_all(&mut ser.cert_pem.as_bytes())?; let certs = pem_certs .into_iter() .filter_map(|cert| match cert { rustls_pemfile::Item::X509Certificate(cert) => Some(rustls::Certificate(cert)), _ => None, }) .collect::>(); let pem_keys = rustls_pemfile::read_all(&mut ser.key_pem.as_bytes())?; let keys = pem_keys .into_iter() .filter_map(|key| match key { rustls_pemfile::Item::RSAKey(bytes) | rustls_pemfile::Item::PKCS8Key(bytes) => { Some(rustls::sign::any_supported_type(&rustls::PrivateKey(bytes)).ok()?) } _ => None, }) .collect::>(); if keys.len() != 1 { bail!("{} keys present in pem file", keys.len()); } let certkey = Arc::new(CertifiedKey::new(certs, keys.into_iter().next().unwrap())); Ok(Cert { ser, certkey }) } pub fn is_old(&self) -> bool { let today = Utc::now().date_naive(); today - self.ser.date > chrono::Duration::days(self.ser.valid_days / 2) } }