use crate::{
account::{AccountBuilder, NoPrivateKey},
api::{responses::DirectoryMeta, Api},
error::Result,
solver::{Solver, SolverManager},
};
use reqwest::Client;
pub const LETS_ENCRYPT_PRODUCTION_URL: &str = "https://acme-v02.api.letsencrypt.org/directory";
pub const LETS_ENCRYPT_STAGING_URL: &str = "https://acme-staging-v02.api.letsencrypt.org/directory";
pub struct DirectoryBuilder {
url: String,
client: Option<Client>,
max_nonces: usize,
solvers: SolverManager,
}
impl DirectoryBuilder {
pub fn new(url: String) -> Self {
DirectoryBuilder {
url,
client: None,
max_nonces: 10,
solvers: SolverManager::default(),
}
}
pub fn client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}
pub fn max_nonces(mut self, max: usize) -> Self {
self.max_nonces = max;
self
}
pub fn dns01_solver(mut self, solver: Box<dyn Solver>) -> Self {
self.solvers.set_dns01_solver(solver);
self
}
pub fn http01_solver(mut self, solver: Box<dyn Solver>) -> Self {
self.solvers.set_http01_solver(solver);
self
}
pub fn tls_alpn01_solver(mut self, solver: Box<dyn Solver>) -> Self {
self.solvers.set_tls_alpn01_solver(solver);
self
}
pub async fn build(self) -> Result<Directory> {
let client = self.client.unwrap_or_else(|| {
Client::builder()
.user_agent(crate::USER_AGENT)
.build()
.unwrap()
});
let api = Api::from_url(self.url, client, self.max_nonces, self.solvers).await?;
Ok(Directory(api))
}
}
#[derive(Clone, Debug)]
pub struct Directory(Api);
impl Directory {
pub fn builder<S: Into<String>>(url: S) -> DirectoryBuilder {
DirectoryBuilder::new(url.into())
}
pub fn account(&self) -> AccountBuilder<NoPrivateKey> {
AccountBuilder::<NoPrivateKey>::new(self.0.clone())
}
#[inline(always)]
pub fn meta(&self) -> &DirectoryMeta {
self.0.meta()
}
pub(crate) fn api(&self) -> &Api {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::{Directory, LETS_ENCRYPT_STAGING_URL};
use crate::test::directory;
use test_log::test;
#[test(tokio::test)]
async fn initialize_lets_encrypt() {
let directory = Directory::builder(LETS_ENCRYPT_STAGING_URL)
.build()
.await
.unwrap();
assert_eq!(
directory.meta().terms_of_service,
Some("https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf".into())
);
assert_eq!(
directory.meta().website,
Some("https://letsencrypt.org/docs/staging-environment/".into())
);
assert_eq!(
directory.meta().caa_identities,
Some(vec!["letsencrypt.org".into()])
);
assert_eq!(directory.meta().external_account_required, None);
}
#[test(tokio::test)]
async fn initialize_pebble() {
let directory = directory().await;
assert_eq!(
directory.meta().terms_of_service,
Some("data:text/plain,Do%20what%20thou%20wilt".into())
);
assert_eq!(directory.meta().website, None);
assert_eq!(directory.meta().caa_identities, None);
assert_eq!(directory.meta().external_account_required, Some(false));
}
}