Browse Source

Propagate async through the request_certificate function

pull/88/head
Rodolphe Bréard 2 years ago
parent
commit
9d43f72466
  1. 103
      acmed/src/acme_proto.rs
  2. 6
      acmed/src/acme_proto/account.rs
  3. 5
      acmed/src/main_event_loop.rs

103
acmed/src/acme_proto.rs

@ -1,14 +1,13 @@
use crate::account::Account;
use crate::acme_proto::structs::{
AcmeError, ApiError, Authorization, AuthorizationStatus, NewOrder, Order, OrderStatus,
};
use crate::certificate::Certificate;
use crate::endpoint::Endpoint;
use crate::http::HttpError;
use crate::identifier::IdentifierType;
use crate::jws::encode_kid;
use crate::logs::HasLogger;
use crate::storage;
use crate::{AccountSync, EndpointSync};
use acme_common::crypto::Csr;
use acme_common::error::Error;
use serde_json::json;
@ -60,49 +59,56 @@ impl PartialEq<structs::Challenge> for Challenge {
}
#[macro_export]
macro_rules! set_data_builder {
($account: ident, $endpoint_name: ident, $data: expr) => {
|n: &str, url: &str| {
macro_rules! set_data_builder_sync {
($account: ident, $endpoint_name: ident, $data: expr) => {{
let endpoint_name = &$endpoint_name;
move |n: &str, url: &str| {
encode_kid(
&$account.current_key.key,
&$account.current_key.signature_algorithm,
&($account.get_endpoint(&$endpoint_name)?.account_url),
&($account.get_endpoint(endpoint_name)?.account_url),
$data,
url,
n,
)
}
};
}};
}
#[macro_export]
macro_rules! set_empty_data_builder {
($account: ident, $endpoint_name: ident) => {
set_data_builder!($account, $endpoint_name, b"")
macro_rules! set_data_builder {
($account: ident, $endpoint_name: ident, $data: expr) => {
async {
let account = $account.read().await;
set_data_builder_sync!(account, $endpoint_name, $data)
}
};
}
pub fn request_certificate(
pub async fn request_certificate(
cert: &Certificate,
endpoint: &mut Endpoint,
account: &mut Account,
account_s: AccountSync,
endpoint_s: EndpointSync,
) -> Result<(), Error> {
let mut hook_datas = vec![];
let endpoint_name = endpoint.name.clone();
let endpoint_name = endpoint_s.read().await.name.clone();
// Refresh the directory
http::refresh_directory(endpoint).map_err(HttpError::in_err)?;
http::refresh_directory(&mut *(endpoint_s.write().await)).map_err(HttpError::in_err)?;
// Synchronize the account
account.synchronize(endpoint)?;
account_s
.write()
.await
.synchronize(&mut *(endpoint_s.write().await))?;
// Create a new order
let mut new_reg = false;
let (order, order_url) = loop {
let new_order = NewOrder::new(&cert.identifiers);
let new_order = serde_json::to_string(&new_order)?;
let data_builder = set_data_builder!(account, endpoint_name, new_order.as_bytes());
match http::new_order(endpoint, &data_builder) {
let data_builder = set_data_builder!(account_s, endpoint_name, new_order.as_bytes()).await;
match http::new_order(&mut *(endpoint_s.write().await), &data_builder) {
Ok((order, order_url)) => {
if let Some(e) = order.get_error() {
cert.warn(&e.prefix("Error").message);
@ -111,7 +117,10 @@ pub fn request_certificate(
}
Err(e) => {
if !new_reg && e.is_acme_err(AcmeError::AccountDoesNotExist) {
account.register(endpoint)?;
account_s
.write()
.await
.register(&mut *(endpoint_s.write().await))?;
new_reg = true;
} else {
return Err(HttpError::in_err(e));
@ -123,8 +132,9 @@ pub fn request_certificate(
// Begin iter over authorizations
for auth_url in order.authorizations.iter() {
// Fetch the authorization
let data_builder = set_empty_data_builder!(account, endpoint_name);
let auth = http::get_authorization(endpoint, &data_builder, auth_url)
let data_builder = set_data_builder!(account_s, endpoint_name, b"").await;
let auth =
http::get_authorization(&mut *(endpoint_s.write().await), &data_builder, auth_url)
.map_err(HttpError::in_err)?;
if let Some(e) = auth.get_error() {
cert.warn(&e.prefix("error").message);
@ -145,7 +155,7 @@ pub fn request_certificate(
let current_challenge = current_identifier.challenge;
for challenge in auth.challenges.iter() {
if current_challenge == *challenge {
let proof = challenge.get_proof(&account.current_key.key)?;
let proof = challenge.get_proof(&account_s.read().await.current_key.key)?;
let file_name = challenge.get_file_name();
let identifier = auth.identifier.value.to_owned();
@ -156,16 +166,25 @@ pub fn request_certificate(
// Tell the server the challenge has been completed
let chall_url = challenge.get_url();
let data_builder = set_data_builder!(account, endpoint_name, b"{}");
http::post_jose_no_response(endpoint, &data_builder, &chall_url)
let data_builder = set_data_builder!(account_s, endpoint_name, b"{}").await;
http::post_jose_no_response(
&mut *(endpoint_s.write().await),
&data_builder,
&chall_url,
)
.map_err(HttpError::in_err)?;
}
}
// Pool the authorization in order to see whether or not it is valid
let data_builder = set_empty_data_builder!(account, endpoint_name);
let data_builder = set_data_builder!(account_s, endpoint_name, b"").await;
let break_fn = |a: &Authorization| a.status == AuthorizationStatus::Valid;
let _ = http::pool_authorization(endpoint, &data_builder, &break_fn, auth_url)
let _ = http::pool_authorization(
&mut *(endpoint_s.write().await),
&data_builder,
&break_fn,
auth_url,
)
.map_err(HttpError::in_err)?;
for (data, hook_type) in hook_datas.iter() {
cert.call_challenge_hooks_clean(data, (*hook_type).to_owned())?;
@ -175,9 +194,14 @@ pub fn request_certificate(
// End iter over authorizations
// Pool the order in order to see whether or not it is ready
let data_builder = set_empty_data_builder!(account, endpoint_name);
let data_builder = set_data_builder!(account_s, endpoint_name, b"").await;
let break_fn = |o: &Order| o.status == OrderStatus::Ready;
let order = http::pool_order(endpoint, &data_builder, &break_fn, &order_url)
let order = http::pool_order(
&mut *(endpoint_s.write().await),
&data_builder,
&break_fn,
&order_url,
)
.map_err(HttpError::in_err)?;
// Finalize the order by sending the CSR
@ -206,26 +230,35 @@ pub fn request_certificate(
"csr": csr.to_der_base64()?,
});
let csr = csr.to_string();
let data_builder = set_data_builder!(account, endpoint_name, csr.as_bytes());
let order = http::finalize_order(endpoint, &data_builder, &order.finalize)
let data_builder = set_data_builder!(account_s, endpoint_name, csr.as_bytes()).await;
let order = http::finalize_order(
&mut *(endpoint_s.write().await),
&data_builder,
&order.finalize,
)
.map_err(HttpError::in_err)?;
if let Some(e) = order.get_error() {
cert.warn(&e.prefix("error").message);
}
// Pool the order in order to see whether or not it is valid
let data_builder = set_empty_data_builder!(account, endpoint_name);
let data_builder = set_data_builder!(account_s, endpoint_name, b"").await;
let break_fn = |o: &Order| o.status == OrderStatus::Valid;
let order = http::pool_order(endpoint, &data_builder, &break_fn, &order_url)
let order = http::pool_order(
&mut *(endpoint_s.write().await),
&data_builder,
&break_fn,
&order_url,
)
.map_err(HttpError::in_err)?;
// Download the certificate
let crt_url = order
.certificate
.ok_or_else(|| Error::from("no certificate available for download"))?;
let data_builder = set_empty_data_builder!(account, endpoint_name);
let crt =
http::get_certificate(endpoint, &data_builder, &crt_url).map_err(HttpError::in_err)?;
let data_builder = set_data_builder!(account_s, endpoint_name, b"").await;
let crt = http::get_certificate(&mut *(endpoint_s.write().await), &data_builder, &crt_url)
.map_err(HttpError::in_err)?;
storage::write_certificate(&cert.file_manager, crt.as_bytes())?;
cert.info(&format!(

6
acmed/src/acme_proto/account.rs

@ -5,7 +5,7 @@ use crate::endpoint::Endpoint;
use crate::http::HttpError;
use crate::jws::{encode_jwk, encode_kid};
use crate::logs::HasLogger;
use crate::set_data_builder;
use crate::set_data_builder_sync;
use acme_common::error::Error;
macro_rules! create_account_if_does_not_exist {
@ -87,7 +87,9 @@ pub fn update_account_contacts(
let new_contacts: Vec<String> = account.contacts.iter().map(|c| c.to_string()).collect();
let acc_up_struct = AccountUpdate::new(&new_contacts);
let acc_up_struct = serde_json::to_string(&acc_up_struct)?;
let data_builder = set_data_builder!(account, endpoint_name, acc_up_struct.as_bytes());
let account_owned = account.clone();
let data_builder =
set_data_builder_sync!(account_owned, endpoint_name, acc_up_struct.as_bytes());
let url = account.get_endpoint(&endpoint_name)?.account_url.clone();
create_account_if_does_not_exist!(
http::post_jose_no_response(endpoint, &data_builder, &url),

5
acmed/src/main_event_loop.rs

@ -189,9 +189,8 @@ async fn renew_certificate(
}
sleep(Duration::from_secs(crate::DEFAULT_SLEEP_TIME)).await;
}
let mut account = account_s.write().await;
let mut endpoint = endpoint_s.write().await;
let (status, is_success) = match request_certificate(certificate, &mut endpoint, &mut account) {
let (status, is_success) =
match request_certificate(certificate, account_s.clone(), endpoint_s.clone()).await {
Ok(_) => ("success".to_string(), true),
Err(e) => {
let e = e.prefix("unable to renew the certificate");

Loading…
Cancel
Save