Postpone certificate retrieval until order is valid
This commit is contained in:
parent
a2d4129201
commit
0cc77ff2ca
|
@ -130,8 +130,15 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
// Finalize the order and print certificate chain, private key and account credentials.
|
// Finalize the order and print certificate chain, private key and account credentials.
|
||||||
|
|
||||||
let cert_chain_pem = order.finalize(&csr).await.unwrap();
|
order.finalize(&csr).await.unwrap();
|
||||||
info!("certficate chain:\n\n{}", cert_chain_pem,);
|
let cert_chain_pem = loop {
|
||||||
|
match order.certificate().await.unwrap() {
|
||||||
|
Some(cert_chain_pem) => break cert_chain_pem,
|
||||||
|
None => sleep(Duration::from_secs(1)).await,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("certficate chain:\n\n{}", cert_chain_pem);
|
||||||
info!("private key:\n\n{}", cert.serialize_private_key_pem());
|
info!("private key:\n\n{}", cert.serialize_private_key_pem());
|
||||||
info!(
|
info!(
|
||||||
"account credentials:\n\n{}",
|
"account credentials:\n\n{}",
|
||||||
|
|
47
src/lib.rs
47
src/lib.rs
|
@ -75,9 +75,9 @@ impl Order {
|
||||||
/// Request a certificate from the given Certificate Signing Request (CSR)
|
/// Request a certificate from the given Certificate Signing Request (CSR)
|
||||||
///
|
///
|
||||||
/// Creating a CSR is outside of the scope of instant-acme. Make sure you pass in a
|
/// Creating a CSR is outside of the scope of instant-acme. Make sure you pass in a
|
||||||
/// DER representation of the CSR in `csr_der`. The resulting `String` will contain the
|
/// DER representation of the CSR in `csr_der`. Call `certificate()` to retrieve the
|
||||||
/// PEM-encoded certificate chain.
|
/// certificate chain once the order is in the appropriate state.
|
||||||
pub async fn finalize(&mut self, csr_der: &[u8]) -> Result<String, Error> {
|
pub async fn finalize(&mut self, csr_der: &[u8]) -> Result<(), Error> {
|
||||||
let rsp = self
|
let rsp = self
|
||||||
.account
|
.account
|
||||||
.post(
|
.post(
|
||||||
|
@ -88,24 +88,51 @@ impl Order {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.nonce = nonce_from_response(&rsp);
|
self.nonce = nonce_from_response(&rsp);
|
||||||
let state = Problem::check::<OrderState>(rsp).await?;
|
self.state = Problem::check::<OrderState>(rsp).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let cert_url = match state.certificate {
|
/// Get the certificate for this order
|
||||||
Some(url) => url,
|
///
|
||||||
None => return Err(Error::Str("no certificate URL")),
|
/// If the cached order state is in `ready` or `processing` state, this will poll the server
|
||||||
|
/// for the latest state. If the order is still in `processing` state after that, this will
|
||||||
|
/// return `Ok(None)`. If the order is in `valid` state, this will attempt to retrieve
|
||||||
|
/// the certificate from the server and return it as a `String`. If the order contains
|
||||||
|
/// an error or ends up in any state other than `valid` or `processing`, return an error.
|
||||||
|
pub async fn certificate(&mut self) -> Result<Option<String>, Error> {
|
||||||
|
if matches!(self.state.status, OrderStatus::Processing) {
|
||||||
|
let rsp = self
|
||||||
|
.account
|
||||||
|
.post(None::<&Empty>, self.nonce.take(), &self.url)
|
||||||
|
.await?;
|
||||||
|
self.nonce = nonce_from_response(&rsp);
|
||||||
|
self.state = Problem::check::<OrderState>(rsp).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(error) = &self.state.error {
|
||||||
|
return Err(Error::Api(error.clone()));
|
||||||
|
} else if self.state.status == OrderStatus::Processing {
|
||||||
|
return Ok(None);
|
||||||
|
} else if self.state.status != OrderStatus::Valid {
|
||||||
|
return Err(Error::Str("invalid order state"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let cert_url = match &self.state.certificate {
|
||||||
|
Some(cert_url) => cert_url,
|
||||||
|
None => return Err(Error::Str("no certificate URL found")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let rsp = self
|
let rsp = self
|
||||||
.account
|
.account
|
||||||
.post(None::<&Empty>, self.nonce.take(), &cert_url)
|
.post(None::<&Empty>, self.nonce.take(), cert_url)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.nonce = nonce_from_response(&rsp);
|
self.nonce = nonce_from_response(&rsp);
|
||||||
let body = hyper::body::to_bytes(Problem::from_response(rsp).await?).await?;
|
let body = hyper::body::to_bytes(Problem::from_response(rsp).await?).await?;
|
||||||
Ok(
|
Ok(Some(
|
||||||
String::from_utf8(body.to_vec())
|
String::from_utf8(body.to_vec())
|
||||||
.map_err(|_| "unable to decode certificate as UTF-8")?,
|
.map_err(|_| "unable to decode certificate as UTF-8")?,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notify the server that the given challenge is ready to be completed
|
/// Notify the server that the given challenge is ready to be completed
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub struct AccountCredentials<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An RFC 7807 problem document as returned by the ACME server
|
/// An RFC 7807 problem document as returned by the ACME server
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Problem {
|
pub struct Problem {
|
||||||
/// One of an enumerated list of problem types
|
/// One of an enumerated list of problem types
|
||||||
|
|
Loading…
Reference in New Issue