1
use std::{sync::Arc, time::Duration};
2

            
3
use async_acme::cache::AcmeCache;
4
use async_trait::async_trait;
5
use bonsaidb_core::{
6
    arc_bytes::serde::Bytes,
7
    connection::Connection,
8
    define_basic_unique_mapped_view,
9
    document::{CollectionDocument, Emit, KeyId},
10
    schema::{Collection, SerializedCollection},
11
};
12
use serde::{Deserialize, Serialize};
13

            
14
use crate::{Backend, CustomServer, Error};
15

            
16
8720
#[derive(Clone, Debug, Serialize, Deserialize, Collection)]
17
#[collection(name = "acme-accounts", authority = "khonsulabs", views = [AcmeAccountByContacts])]
18
#[collection(encryption_key = Some(KeyId::Master), encryption_optional, core = bonsaidb_core)]
19
pub struct AcmeAccount {
20
    pub contacts: Vec<String>,
21
    pub data: Bytes,
22
}
23

            
24
define_basic_unique_mapped_view!(
25
    AcmeAccountByContacts,
26
    AcmeAccount,
27
    1,
28
    "by-contacts",
29
    String,
30
    |document: CollectionDocument<AcmeAccount>| {
31
        document
32
            .header
33
            .emit_key(document.contents.contacts.join(";"))
34
    }
35
);
36

            
37
#[async_trait]
38
impl<B: Backend> AcmeCache for CustomServer<B> {
39
    type Error = Error;
40

            
41
    async fn read_account(&self, contacts: &[&str]) -> Result<Option<Vec<u8>>, Self::Error> {
42
        let db = self.hosted().await;
43
        let contact = db
44
            .view::<AcmeAccountByContacts>()
45
            .with_key(contacts.join(";"))
46
            .query_with_collection_docs()
47
            .await?
48
            .documents
49
            .into_iter()
50
            .next();
51

            
52
        if let Some((_, contact)) = contact {
53
            Ok(Some(contact.contents.data.into_vec()))
54
        } else {
55
            Ok(None)
56
        }
57
    }
58

            
59
    async fn write_account(&self, contacts: &[&str], contents: &[u8]) -> Result<(), Self::Error> {
60
        let db = self.hosted().await;
61
        let mapped_account = db
62
            .view::<AcmeAccountByContacts>()
63
            .with_key(contacts.join(";"))
64
            .query_with_collection_docs()
65
            .await?
66
            .documents
67
            .into_iter()
68
            .next();
69
        if let Some((_, mut account)) = mapped_account {
70
            account.contents.data = Bytes::from(contents);
71
            account.update(&db).await?;
72
        } else {
73
            AcmeAccount {
74
                contacts: contacts.iter().map(|&c| c.to_string()).collect(),
75
                data: Bytes::from(contents),
76
            }
77
            .push_into(&db)
78
            .await?;
79
        }
80

            
81
        Ok(())
82
    }
83

            
84
    async fn write_certificate(
85
        &self,
86
        _domains: &[String],
87
        _directory_url: &str,
88
        key_pem: &str,
89
        certificate_pem: &str,
90
    ) -> Result<(), Self::Error> {
91
        self.install_pem_certificate(certificate_pem.as_bytes(), key_pem.as_bytes())
92
            .await
93
    }
94
}
95

            
96
impl<B: Backend> CustomServer<B> {
97
1
    pub(crate) async fn update_acme_certificates(&self) -> Result<(), Error> {
98
        loop {
99
            {
100
1
                let key = self.data.primary_tls_key.lock().clone();
101
1
                while async_acme::rustls_helper::duration_until_renewal_attempt(key.as_deref(), 0)
102
1
                    > Duration::from_secs(24 * 60 * 60 * 14)
103
                {
104
1
                    tokio::time::sleep(Duration::from_secs(60 * 60)).await;
105
                }
106
            }
107

            
108
            log::info!(
109
                "requesting new tls certificate for {}",
110
                self.data.primary_domain
111
            );
112
            let domains = vec![self.data.primary_domain.clone()];
113
            async_acme::rustls_helper::order(
114
                |domain, key| {
115
                    let mut auth_keys = self.data.alpn_keys.lock().unwrap();
116
                    auth_keys.insert(domain, Arc::new(key));
117
                    Ok(())
118
                },
119
                &self.data.acme.directory,
120
                &domains,
121
                Some(self),
122
                &self
123
                    .data
124
                    .acme
125
                    .contact_email
126
                    .iter()
127
                    .cloned()
128
                    .collect::<Vec<_>>(),
129
            )
130
            .await?;
131
        }
132
    }
133
}