async_acme/
lib.rs

1/*! A generic async ACME create.
2
3Binaries can choose what async runtime and TLS lib is used.
4
5You need to specify via features what crates are used to the actual work.
6Without anything specified you will end up with *no async backend selected* or *no crypto backend selected*.
7
8To get a certificate from an ACME provider you
9create an [`acme::Account`] and then drive the order on it.
10Refer to [`acme::Account`] for the steps of a Order.
11```
12use async_acme::{
13    acme::{LETS_ENCRYPT_STAGING_DIRECTORY, Directory, Account},
14
15};
16async fn create_account() -> Account {
17    let cache = "./cachedir/".to_string();
18    let directory = Directory::discover(LETS_ENCRYPT_STAGING_DIRECTORY).await.unwrap();
19    Account::load_or_create(
20        directory,
21        Some(&cache),
22        &vec!["mailto:admin@example.com".to_string()]
23    ).await.unwrap()
24}
25```
26
27If you are using rustls, you probably want to just use [`rustls_helper::order`].
28
29[`rustls_helper::order`]: ./rustls_helper/fn.order.html
30[`acme::Account`]: ./acme/struct.Account.html
31*/
32#![cfg_attr(docsrs, feature(doc_cfg))]
33
34use base64::{
35    alphabet::URL_SAFE,
36    engine::{general_purpose::NO_PAD, GeneralPurpose},
37};
38
39const B64_URL_SAFE_NO_PAD: GeneralPurpose = GeneralPurpose::new(&URL_SAFE, NO_PAD);
40
41pub mod acme;
42pub mod cache;
43mod crypto;
44mod jose;
45
46#[cfg(any(feature = "rustls_ring", feature = "rustls_aws_lc_rs"))]
47#[cfg_attr(docsrs, doc(cfg(any(feature = "rustls_ring", feature = "rustls_aws_lc_rs"))))]
48pub mod rustls_helper;
49
50#[cfg(test)]
51#[cfg(any(feature = "use_async_std", feature = "use_tokio"))]
52pub(crate) mod test {
53    #[cfg(feature = "use_async_std")]
54    pub(crate) use async_std::{
55        io::prelude::{ReadExt, WriteExt},
56        net::{TcpListener, TcpStream},
57        task::spawn,
58    };
59    #[cfg(feature = "use_async_std")]
60    pub(crate) fn block_on(
61        fut: impl std::future::Future<Output = Result<(), Box<dyn std::error::Error>>>,
62    ) {
63        async_std::task::block_on(fut).expect("block_on failed")
64    }
65    //use futures::{AsyncWriteExt};
66    #[cfg(feature = "use_tokio")]
67    pub(crate) use tokio::{
68        io::{AsyncReadExt as ReadExt, AsyncWriteExt as WriteExt},
69        net::{TcpListener, TcpStream},
70        runtime::Builder,
71    };
72    #[cfg(feature = "use_tokio")]
73    pub(crate) fn block_on(
74        fut: impl std::future::Future<Output = Result<(), Box<dyn std::error::Error>>>,
75    ) {
76        Builder::new_current_thread()
77            .enable_all()
78            .build()
79            .expect("rt")
80            .block_on(fut)
81            .expect("block_on failed")
82    }
83    #[cfg(feature = "use_tokio")]
84    pub(crate) fn spawn<T>(fut: T) -> impl std::future::Future<Output = T::Output>
85    where
86        T: std::future::Future + Send + 'static,
87        T::Output: Send + 'static,
88    {
89        let jh = tokio::task::spawn(fut);
90        async { jh.await.expect("spawn failed") }
91    }
92    pub(crate) async fn close(mut stream: TcpStream) -> std::io::Result<()> {
93        stream.flush().await?;
94        #[cfg(feature = "use_tokio")]
95        stream.shutdown().await?;
96        #[cfg(feature = "use_async_std")]
97        stream.shutdown(async_std::net::Shutdown::Both)?;
98        Ok(())
99    }
100
101    pub(crate) async fn assert_stream(
102        stream: &mut TcpStream,
103        should_be: &[u8],
104    ) -> std::io::Result<()> {
105        let l = should_be.len();
106        let mut req: Vec<u8> = vec![0; l];
107        let _r = stream.read(req.as_mut_slice()).await?;
108        assert_eq!(req, should_be);
109        Ok(())
110    }
111    pub(crate) async fn listen_somewhere() -> Result<(TcpListener, u16, String), std::io::Error> {
112        let listener = TcpListener::bind("127.0.0.1:0").await?;
113        let addr = listener.local_addr()?;
114        Ok((listener, addr.port(), addr.ip().to_string()))
115    }
116}