bonsaidb_server/server/
acme.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use async_acme::cache::AcmeCache;
5use async_trait::async_trait;
6use bonsaidb_core::arc_bytes::serde::Bytes;
7use bonsaidb_core::connection::AsyncConnection;
8use bonsaidb_core::define_basic_unique_mapped_view;
9use bonsaidb_core::document::{CollectionDocument, Emit, KeyId};
10use bonsaidb_core::schema::{Collection, SerializedCollection};
11use serde::{Deserialize, Serialize};
12
13use crate::{Backend, CustomServer, Error};
14
15#[derive(Clone, Debug, Serialize, Deserialize, Collection)]
16#[collection(name = "acme-accounts", authority = "khonsulabs", views = [AcmeAccountByContacts])]
17#[collection(encryption_key = Some(KeyId::Master), encryption_optional, core = bonsaidb_core)]
18pub struct AcmeAccount {
19    pub contacts: Vec<String>,
20    pub data: Bytes,
21}
22
23define_basic_unique_mapped_view!(
24    AcmeAccountByContacts,
25    AcmeAccount,
26    1,
27    "by-contacts",
28    String,
29    |document: CollectionDocument<AcmeAccount>| {
30        document
31            .header
32            .emit_key(document.contents.contacts.join(";"))
33    }
34);
35
36#[async_trait]
37impl<B: Backend> AcmeCache for CustomServer<B> {
38    type Error = Error;
39
40    async fn read_account(&self, contacts: &[&str]) -> Result<Option<Vec<u8>>, Self::Error> {
41        let db = self.hosted().await;
42        let contact = db
43            .view::<AcmeAccountByContacts>()
44            .with_key(&contacts.join(";"))
45            .query_with_collection_docs()
46            .await?
47            .documents
48            .into_iter()
49            .next();
50
51        if let Some((_, contact)) = contact {
52            Ok(Some(contact.contents.data.into_vec()))
53        } else {
54            Ok(None)
55        }
56    }
57
58    async fn write_account(&self, contacts: &[&str], contents: &[u8]) -> Result<(), Self::Error> {
59        let db = self.hosted().await;
60        let mapped_account = db
61            .view::<AcmeAccountByContacts>()
62            .with_key(&contacts.join(";"))
63            .query_with_collection_docs()
64            .await?
65            .documents
66            .into_iter()
67            .next();
68        if let Some((_, mut account)) = mapped_account {
69            account.contents.data = Bytes::from(contents);
70            account.update_async(&db).await?;
71        } else {
72            AcmeAccount {
73                contacts: contacts.iter().map(|&c| c.to_string()).collect(),
74                data: Bytes::from(contents),
75            }
76            .push_into_async(&db)
77            .await?;
78        }
79
80        Ok(())
81    }
82
83    async fn write_certificate(
84        &self,
85        _domains: &[String],
86        _directory_url: &str,
87        key_pem: &str,
88        certificate_pem: &str,
89    ) -> Result<(), Self::Error> {
90        self.install_pem_certificate(certificate_pem.as_bytes(), key_pem.as_bytes())
91            .await
92    }
93}
94
95impl<B: Backend> CustomServer<B> {
96    pub(crate) async fn update_acme_certificates(&self) -> Result<(), Error> {
97        loop {
98            {
99                let key = self.data.primary_tls_key.lock().clone();
100                while async_acme::rustls_helper::duration_until_renewal_attempt(key.as_deref(), 0)
101                    > Duration::from_secs(24 * 60 * 60 * 14)
102                {
103                    tokio::time::sleep(Duration::from_secs(60 * 60)).await;
104                }
105            }
106
107            log::info!(
108                "requesting new tls certificate for {}",
109                self.data.primary_domain
110            );
111            let domains = vec![self.data.primary_domain.clone()];
112            async_acme::rustls_helper::order(
113                |domain, key| {
114                    let mut auth_keys = self.data.alpn_keys.lock();
115                    auth_keys.insert(domain, Arc::new(key));
116                    Ok(())
117                },
118                &self.data.acme.directory,
119                &domains,
120                Some(self),
121                &self
122                    .data
123                    .acme
124                    .contact_email
125                    .iter()
126                    .cloned()
127                    .collect::<Vec<_>>(),
128            )
129            .await?;
130        }
131    }
132}