-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4d889e6
commit 9e79a48
Showing
7 changed files
with
155 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,31 +5,37 @@ use crate::{ | |
log::*, | ||
}; | ||
use rustc_hash::FxHashMap as HashMap; | ||
// use rustls_acme::AcmeConfig; | ||
use std::path::PathBuf; | ||
use rustls::ServerConfig; | ||
use rustls_acme::AcmeConfig; | ||
use std::{path::PathBuf, sync::Arc}; | ||
use tokio::runtime::Handle; | ||
use tokio_stream::StreamExt; | ||
use url::Url; | ||
|
||
#[derive(Debug)] | ||
#[derive(Debug, Clone)] | ||
/// ACME settings | ||
pub struct AcmeContexts { | ||
pub struct AcmeManager { | ||
/// ACME directory url | ||
acme_dir_url: Url, | ||
/// ACME registry directory | ||
acme_registry_dir: PathBuf, | ||
// /// ACME registry directory | ||
// acme_registry_dir: PathBuf, | ||
/// ACME contacts | ||
contacts: Vec<String>, | ||
/// ACME directly cache information | ||
inner: HashMap<String, DirCache>, | ||
/// Tokio runtime handle | ||
runtime_handle: Handle, | ||
} | ||
|
||
impl AcmeContexts { | ||
impl AcmeManager { | ||
/// Create a new instance. Note that for each domain, a new AcmeConfig is created. | ||
/// This means that for each domain, a distinct operation will be dispatched and separated certificates will be generated. | ||
pub fn try_new( | ||
acme_dir_url: Option<&str>, | ||
acme_registry_dir: Option<&str>, | ||
contacts: &[String], | ||
domains: &[String], | ||
runtime_handle: Handle, | ||
) -> Result<Self, RpxyAcmeError> { | ||
// Install aws_lc_rs as default crypto provider for rustls | ||
let _ = rustls::crypto::CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); | ||
|
@@ -45,11 +51,6 @@ impl AcmeContexts { | |
.as_deref() | ||
.map_or_else(|| Url::parse(ACME_DIR_URL), Url::parse)?; | ||
let contacts = contacts.iter().map(|email| format!("mailto:{email}")).collect::<Vec<_>>(); | ||
// let rustls_client_config = rustls::ClientConfig::builder() | ||
// .dangerous() // The `Verifier` we're using is actually safe | ||
// .with_custom_certificate_verifier(std::sync::Arc::new(rustls_platform_verifier::Verifier::new())) | ||
// .with_no_client_auth(); | ||
// let rustls_client_config = Arc::new(rustls_client_config); | ||
|
||
let inner = domains | ||
.iter() | ||
|
@@ -59,27 +60,59 @@ impl AcmeContexts { | |
(domain, dir_cache) | ||
}) | ||
.collect::<HashMap<_, _>>(); | ||
// let inner = domains | ||
// .iter() | ||
// .map(|domain| { | ||
// let dir_cache = DirCache::new(&acme_registry_dir, domain); | ||
// let config = AcmeConfig::new([domain]) | ||
// .contact(&contacts) | ||
// .cache(dir_cache) | ||
// .directory(acme_dir_url.as_str()) | ||
// .client_tls_config(rustls_client_config.clone()); | ||
// let config = Box::new(config); | ||
// (domain.to_ascii_lowercase(), config) | ||
// }) | ||
// .collect::<HashMap<_, _>>(); | ||
|
||
Ok(Self { | ||
acme_dir_url, | ||
acme_registry_dir, | ||
// acme_registry_dir, | ||
contacts, | ||
inner, | ||
runtime_handle, | ||
}) | ||
} | ||
|
||
/// Start ACME manager to manage certificates for each domain. | ||
/// Returns a Vec<JoinHandle<()>> as a tasks handles and a map of domain to ServerConfig for challenge. | ||
pub fn spawn_manager_tasks(&self) -> (Vec<tokio::task::JoinHandle<()>>, HashMap<String, Arc<ServerConfig>>) { | ||
info!("rpxy ACME manager started"); | ||
|
||
let rustls_client_config = rustls::ClientConfig::builder() | ||
.dangerous() // The `Verifier` we're using is actually safe | ||
.with_custom_certificate_verifier(Arc::new(rustls_platform_verifier::Verifier::new())) | ||
.with_no_client_auth(); | ||
let rustls_client_config = Arc::new(rustls_client_config); | ||
|
||
let mut server_configs_for_challenge: HashMap<String, Arc<ServerConfig>> = HashMap::default(); | ||
let join_handles = self | ||
.inner | ||
.clone() | ||
.into_iter() | ||
.map(|(domain, dir_cache)| { | ||
let config = AcmeConfig::new([&domain]) | ||
.contact(&self.contacts) | ||
.cache(dir_cache.to_owned()) | ||
.directory(self.acme_dir_url.as_str()) | ||
.client_tls_config(rustls_client_config.clone()); | ||
let mut state = config.state(); | ||
server_configs_for_challenge.insert(domain.to_ascii_lowercase(), state.challenge_rustls_config()); | ||
self.runtime_handle.spawn(async move { | ||
info!("rpxy ACME manager task for {domain} started"); | ||
// infinite loop unless the return value is None | ||
loop { | ||
let Some(res) = state.next().await else { | ||
error!("rpxy ACME manager task for {domain} exited"); | ||
break; | ||
}; | ||
match res { | ||
Ok(ok) => info!("rpxy ACME event: {ok:?}"), | ||
Err(err) => error!("rpxy ACME error: {err:?}"), | ||
} | ||
} | ||
}) | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
(join_handles, server_configs_for_challenge) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
|
@@ -93,17 +126,19 @@ mod tests { | |
let acme_dir_url = "https://acme.example.com/directory"; | ||
let acme_registry_dir = "/tmp/acme"; | ||
let contacts = vec!["[email protected]".to_string()]; | ||
let acme_contexts: AcmeContexts = AcmeContexts::try_new( | ||
let handle = Handle::current(); | ||
let acme_contexts: AcmeManager = AcmeManager::try_new( | ||
Some(acme_dir_url), | ||
Some(acme_registry_dir), | ||
&contacts, | ||
&["example.com".to_string(), "example.org".to_string()], | ||
handle, | ||
) | ||
.unwrap(); | ||
assert_eq!(acme_contexts.inner.len(), 2); | ||
assert_eq!(acme_contexts.contacts, vec!["mailto:[email protected]".to_string()]); | ||
assert_eq!(acme_contexts.acme_dir_url.as_str(), acme_dir_url); | ||
assert_eq!(acme_contexts.acme_registry_dir, PathBuf::from(acme_registry_dir)); | ||
// assert_eq!(acme_contexts.acme_registry_dir, PathBuf::from(acme_registry_dir)); | ||
assert_eq!( | ||
acme_contexts.inner["example.com"], | ||
DirCache { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters