1use std::{
4 fmt::{Debug, Formatter, Result as FmtResult},
5 sync::{Arc, RwLock},
6};
7
8use links_domainmap::{Domain, DomainMap};
9use tokio_rustls::rustls::{
10 server::{ClientHello, ResolvesServerCert},
11 sign::CertifiedKey,
12};
13use tracing::debug;
14
15use crate::util::Unpoison;
16
17pub struct CertificateResolver {
25 certs: RwLock<DomainMap<Arc<CertifiedKey>>>,
27 default: RwLock<Option<Arc<CertifiedKey>>>,
29}
30
31impl CertificateResolver {
32 #[must_use]
34 pub const fn new() -> Self {
35 Self {
36 certs: RwLock::new(DomainMap::new()),
37 default: RwLock::new(None),
38 }
39 }
40
41 fn get_default(&self) -> Option<Arc<CertifiedKey>> {
43 self.default.read().unpoison().as_ref().map(Arc::clone)
44 }
45
46 pub fn get(&self, domain: Option<&Domain>) -> Option<Arc<CertifiedKey>> {
49 domain.map_or_else(
50 || self.get_default(),
51 |domain| {
52 self.certs
53 .read()
54 .unpoison()
55 .get(domain)
56 .map_or_else(|| self.get_default(), |certkey| Some(Arc::clone(certkey)))
57 },
58 )
59 }
60
61 pub fn set(&self, domain: Domain, certkey: Arc<CertifiedKey>) {
64 self.certs.write().unpoison().set(domain, certkey);
65 }
66
67 pub fn set_default(&self, certkey: Option<Arc<CertifiedKey>>) {
73 *self.default.write().unpoison() = certkey;
74 }
75
76 pub fn remove(&self, domain: &Domain) {
79 self.certs.write().unpoison().remove(domain);
80 }
81}
82
83impl Default for CertificateResolver {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89impl ResolvesServerCert for CertificateResolver {
90 fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
91 let cert = self.get(
92 client_hello
93 .server_name()
94 .map(Domain::reference)
95 .and_then(Result::ok)
96 .as_ref(),
97 );
98
99 if cert.is_none() {
100 debug!(
101 "Certificate for {:?} not resolved",
102 client_hello.server_name()
103 );
104 }
105
106 cert
107 }
108}
109
110impl Debug for CertificateResolver {
111 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
112 f.debug_struct("CertificateResolver")
113 .field("current", &"Arc<[REDACTED]>")
114 .finish()
115 }
116}