1use openssl::pkey::{self, PKey};
21use std::sync::Arc;
22use std::thread;
23use std::time::Duration;
24
25use crate::acc::AccountInner;
26use crate::api::{ApiAuth, ApiEmptyString, ApiFinalize, ApiOrder};
27use crate::cert::{create_csr, Certificate};
28use crate::persist::{Persist, PersistKey, PersistKind};
29use crate::util::{base64url, read_json};
30use crate::Result;
31
32mod auth;
33
34pub use self::auth::{Auth, Challenge};
35
36pub(crate) struct Order<P: Persist> {
38 inner: Arc<AccountInner<P>>,
39 api_order: ApiOrder,
40 url: String,
41}
42
43impl<P: Persist> Order<P> {
44 pub(crate) fn new(inner: &Arc<AccountInner<P>>, api_order: ApiOrder, url: String) -> Self {
45 Order {
46 inner: inner.clone(),
47 api_order,
48 url,
49 }
50 }
51}
52
53pub(crate) fn refresh_order<P: Persist>(
55 inner: &Arc<AccountInner<P>>,
56 url: String,
57 want_status: &'static str,
58) -> Result<Order<P>> {
59 let res = inner.transport.call(&url, &ApiEmptyString)?;
60
61 let api_order = api_order_of(res, want_status)?;
64
65 Ok(Order {
66 inner: inner.clone(),
67 api_order,
68 url,
69 })
70}
71
72#[cfg(not(test))]
73fn api_order_of(res: ureq::Response, _want_status: &str) -> Result<ApiOrder> {
74 read_json(res)
75}
76
77#[cfg(test)]
78fn api_order_of(res: ureq::Response, want_status: &str) -> Result<ApiOrder> {
80 let s = res.into_string()?;
81 #[allow(clippy::trivial_regex)]
82 let re = regex::Regex::new("<STATUS>").unwrap();
83 let b = re.replace_all(&s, want_status).to_string();
84 let api_order: ApiOrder = serde_json::from_str(&b)?;
85 Ok(api_order)
86}
87
88pub struct NewOrder<P: Persist> {
105 pub(crate) order: Order<P>,
106}
107
108impl<P: Persist> NewOrder<P> {
109 pub fn is_validated(&self) -> bool {
118 self.order.api_order.is_status_ready() || self.order.api_order.is_status_valid()
119 }
120
121 pub fn confirm_validations(&self) -> Option<CsrOrder<P>> {
128 if self.is_validated() {
129 Some(CsrOrder {
130 order: Order::new(
131 &self.order.inner,
132 self.order.api_order.clone(),
133 self.order.url.clone(),
134 ),
135 })
136 } else {
137 None
138 }
139 }
140
141 pub fn refresh(&mut self) -> Result<()> {
145 let order = refresh_order(&self.order.inner, self.order.url.clone(), "ready")?;
146 self.order = order;
147 Ok(())
148 }
149
150 pub fn authorizations(&self) -> Result<Vec<Auth<P>>> {
157 let mut result = vec![];
158 if let Some(authorizations) = &self.order.api_order.authorizations {
159 for auth_url in authorizations {
160 let res = self.order.inner.transport.call(auth_url, &ApiEmptyString)?;
161 let api_auth: ApiAuth = read_json(res)?;
162 result.push(Auth::new(&self.order.inner, api_auth, auth_url));
163 }
164 }
165 Ok(result)
166 }
167
168 pub fn api_order(&self) -> &ApiOrder {
170 &self.order.api_order
171 }
172}
173
174pub struct CsrOrder<P: Persist> {
195 pub(crate) order: Order<P>,
196}
197
198impl<P: Persist> CsrOrder<P> {
199 pub fn finalize(self, private_key_pem: &str, delay_millis: u64) -> Result<CertOrder<P>> {
209 let pkey_pri = PKey::private_key_from_pem(private_key_pem.as_bytes())
210 .map_err(|e| format!("Error reading private key PEM: {}", e))?;
211 self.finalize_pkey(pkey_pri, delay_millis)
212 }
213
214 pub fn finalize_pkey(
222 self,
223 private_key: PKey<pkey::Private>,
224 delay_millis: u64,
225 ) -> Result<CertOrder<P>> {
226 let domains = self.order.api_order.domains();
229
230 let csr = create_csr(&private_key, &domains)?;
232
233 let csr_der = csr.to_der().expect("to_der()");
235 let csr_enc = base64url(&csr_der);
236 let finalize = ApiFinalize { csr: csr_enc };
237
238 let inner = self.order.inner;
239 let order_url = self.order.url;
240 let finalize_url = &self.order.api_order.finalize;
241
242 inner.transport.call(finalize_url, &finalize)?;
245
246 let order = wait_for_order_status(&inner, &order_url, delay_millis)?;
250
251 if !order.api_order.is_status_valid() {
252 return Err(format!("Order is in status: {:?}", order.api_order.status).into());
253 }
254
255 Ok(CertOrder { private_key, order })
256 }
257
258 pub fn api_order(&self) -> &ApiOrder {
260 &self.order.api_order
261 }
262}
263
264fn wait_for_order_status<P: Persist>(
265 inner: &Arc<AccountInner<P>>,
266 url: &str,
267 delay_millis: u64,
268) -> Result<Order<P>> {
269 loop {
270 let order = refresh_order(inner, url.to_string(), "valid")?;
271 if !order.api_order.is_status_processing() {
272 return Ok(order);
273 }
274 thread::sleep(Duration::from_millis(delay_millis));
275 }
276}
277
278pub struct CertOrder<P: Persist> {
280 private_key: PKey<pkey::Private>,
281 order: Order<P>,
282}
283
284impl<P: Persist> CertOrder<P> {
285 pub fn download_and_save_cert(self) -> Result<Certificate> {
292 let primary_name = self.order.api_order.domains()[0].to_string();
294 let url = self.order.api_order.certificate.expect("certificate url");
295 let inner = self.order.inner;
296 let realm = &inner.realm[..];
297
298 let res = inner.transport.call(&url, &ApiEmptyString)?;
299
300 let persist = &inner.persist;
302 let pk_key = PersistKey::new(realm, PersistKind::PrivateKey, &primary_name);
303 let pkey_pem_bytes = self.private_key.private_key_to_pem_pkcs8().expect("to_pem");
304 let pkey_pem = String::from_utf8_lossy(&pkey_pem_bytes);
305 debug!("Save private key: {}", pk_key);
306 persist.put(&pk_key, &pkey_pem_bytes)?;
307
308 let cert = res.into_string()?;
309 let pk_crt = PersistKey::new(realm, PersistKind::Certificate, &primary_name);
310 debug!("Save certificate: {}", pk_crt);
311 persist.put(&pk_crt, cert.as_bytes())?;
312
313 Ok(Certificate::new(pkey_pem.to_string(), cert))
314 }
315
316 pub fn api_order(&self) -> &ApiOrder {
318 &self.order.api_order
319 }
320}
321
322#[cfg(test)]
323mod test {
324 use super::*;
325 use crate::persist::*;
326 use crate::*;
327
328 #[test]
329 fn test_get_authorizations() -> Result<()> {
330 let server = crate::test::with_directory_server();
331 let url = DirectoryUrl::Other(&server.dir_url);
332 let persist = MemoryPersist::new();
333 let dir = Directory::from_url(persist, url)?;
334 let acc = dir.account("foo@bar.com")?;
335 let ord = acc.new_order("acmetest.example.com", &[])?;
336 let _ = ord.authorizations()?;
337 Ok(())
338 }
339
340 #[test]
341 fn test_finalize() -> Result<()> {
342 let server = crate::test::with_directory_server();
343 let url = DirectoryUrl::Other(&server.dir_url);
344 let persist = MemoryPersist::new();
345 let dir = Directory::from_url(persist, url)?;
346 let acc = dir.account("foo@bar.com")?;
347 let ord = acc.new_order("acmetest.example.com", &[])?;
348 let ord = CsrOrder { order: ord.order };
350 let pkey = cert::create_p256_key();
351 let _ord = ord.finalize_pkey(pkey, 1)?;
352 Ok(())
353 }
354
355 #[test]
356 fn test_download_and_save_cert() -> Result<()> {
357 let server = crate::test::with_directory_server();
358 let url = DirectoryUrl::Other(&server.dir_url);
359 let persist = MemoryPersist::new();
360 let dir = Directory::from_url(persist, url)?;
361 let acc = dir.account("foo@bar.com")?;
362 let ord = acc.new_order("acmetest.example.com", &[])?;
363
364 let ord = CsrOrder { order: ord.order };
366 let pkey = cert::create_p256_key();
367 let ord = ord.finalize_pkey(pkey, 1)?;
368
369 let cert = ord.download_and_save_cert()?;
370 assert_eq!("CERT HERE", cert.certificate());
371 assert!(!cert.private_key().is_empty());
372
373 let cert2 = acc.certificate("acmetest.example.com")?.unwrap();
375 assert_eq!(cert.private_key(), cert2.private_key());
376 assert_eq!(cert.certificate(), cert2.certificate());
377 assert_eq!(cert.valid_days_left(), 89);
378
379 Ok(())
380 }
381}