33//! checks if certificates are not outdated,
44//! persists files on disk.
55
6+ use crate :: errors:: AtomicServerResult ;
7+ use actix_web:: { dev:: ServerHandle , App , HttpServer } ;
68use std:: {
79 fs:: { self , File } ,
810 io:: BufReader ,
911 path:: PathBuf ,
1012} ;
13+ use tracing:: { info, warn} ;
1114
12- use crate :: errors:: AtomicServerResult ;
1315/// Create RUSTLS server config from certificates in config dir
1416pub fn get_https_config (
1517 config : & crate :: config:: Config ,
@@ -18,7 +20,6 @@ pub fn get_https_config(
1820 let https_config = rustls:: ServerConfig :: builder ( )
1921 . with_safe_defaults ( )
2022 . with_no_client_auth ( ) ;
21- // rustls::NoClientAuth::new()
2223 let cert_file =
2324 & mut BufReader :: new ( File :: open ( config. cert_path . clone ( ) ) . expect ( "No HTTPS TLS key found." ) ) ;
2425 let key_file =
@@ -65,7 +66,7 @@ fn set_certs_created_at_file(config: &crate::config::Config) {
6566/// Will be true if there are no certs yet.
6667pub fn should_renew_certs_check ( config : & crate :: config:: Config ) -> AtomicServerResult < bool > {
6768 if std:: fs:: File :: open ( & config. cert_path ) . is_err ( ) {
68- warn ! (
69+ info ! (
6970 "No HTTPS certificates found in {:?}, requesting new ones..." ,
7071 & config. https_path
7172 ) ;
@@ -87,17 +88,12 @@ pub fn should_renew_certs_check(config: &crate::config::Config) -> AtomicServerR
8788 Ok ( expired)
8889}
8990
90- use actix_web:: { dev:: ServerHandle , App , HttpServer } ;
91- use instant_acme:: { KeyAuthorization , OrderStatus } ;
92- use tracing:: { info, log:: warn} ;
93-
94- use std:: sync:: mpsc;
95-
96- /// Starts an HTTP Actix server for HTTPS certificate initialization
91+ /// Starts an HTTP Actix server for HTTPS certificate initialization.
92+ /// Hosts `.well-known/acme-challenge` folder and the challenge file.
9793async fn cert_init_server (
9894 config : & crate :: config:: Config ,
9995 challenge : & instant_acme:: Challenge ,
100- key_auth : & KeyAuthorization ,
96+ key_auth : & instant_acme :: KeyAuthorization ,
10197) -> AtomicServerResult < ServerHandle > {
10298 let address = format ! ( "{}:{}" , config. opts. ip, config. opts. port) ;
10399 warn ! ( "Server temporarily running in HTTP mode at {}, running Let's Encrypt Certificate initialization..." , address) ;
@@ -117,10 +113,10 @@ async fn cert_init_server(
117113 challenge_path. push ( "acme-challenge" ) ;
118114 fs:: create_dir_all ( & challenge_path) ?;
119115 challenge_path. push ( & challenge. token ) ;
120- // let challenge_file_content = format!("{}.{}", challenge.token, key_auth.as_str());
121116 fs:: write ( challenge_path, key_auth. as_str ( ) ) ?;
122117
123- let ( tx, rx) = mpsc:: channel ( ) ;
118+ // Channel is used to send the server handle back to the main thread, so we can stop it later
119+ let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
124120
125121 std:: thread:: spawn ( move || {
126122 actix_web:: rt:: System :: new ( ) . block_on ( async move {
@@ -153,20 +149,20 @@ async fn cert_init_server(
153149 & config. opts. domain, & challenge. token
154150 ) ;
155151
156- // wait for a few secs
157152 std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 2 ) ) ;
158153 info ! ( "Testing availability of {}" , & well_known_url) ;
159154
160155 let agent = ureq:: builder ( )
161156 . timeout ( std:: time:: Duration :: from_secs ( 2 ) )
162157 . build ( ) ;
163- let resp = agent
164- . get ( & well_known_url)
165- // .get("https://docs.certifytheweb.com/docs/http-validation/")
166- . call ( )
167- . map_err ( |e| format ! ( "Unable to Test local server. {}" , e) ) ?;
158+ let resp = agent. get ( & well_known_url) . call ( ) . map_err ( |e| {
159+ format ! (
160+ "Unable to test local server. Is it available at the right address? {}" ,
161+ e
162+ )
163+ } ) ?;
168164 if resp. status ( ) != 200 {
169- warn ! ( "Unable to Test local server. Status: {}" , resp. status( ) ) ;
165+ warn ! ( "Unable to test local server. Status: {}" , resp. status( ) ) ;
170166 } else {
171167 info ! ( "Server for HTTP initialization running correctly" ) ;
172168 }
@@ -175,6 +171,8 @@ async fn cert_init_server(
175171
176172/// Sends a request to LetsEncrypt to create a certificate
177173pub async fn request_cert ( config : & crate :: config:: Config ) -> AtomicServerResult < ( ) > {
174+ use instant_acme:: OrderStatus ;
175+
178176 let challenge_type = if config. opts . https_dns {
179177 info ! ( "Using DNS-01 challenge" ) ;
180178 instant_acme:: ChallengeType :: Dns01
@@ -188,6 +186,9 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
188186 // using `Account::from_credentials()`.
189187
190188 let lets_encrypt_url = if config. opts . development {
189+ warn ! (
190+ "Using LetsEncrypt staging server, not production. This is for testing purposes only and will not provide a working certificate."
191+ ) ;
191192 instant_acme:: LetsEncrypt :: Staging . url ( )
192193 } else {
193194 instant_acme:: LetsEncrypt :: Production . url ( )
@@ -253,7 +254,7 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
253254 . challenges
254255 . iter ( )
255256 . find ( |c| c. r#type == challenge_type)
256- . ok_or ( "no Dns01 challenge found" ) ?;
257+ . ok_or ( format ! ( "no {:?} challenge found" , challenge_type ) ) ?;
257258
258259 let instant_acme:: Identifier :: Dns ( identifier) = & authz. identifier ;
259260
@@ -278,7 +279,8 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
278279 }
279280
280281 // Let the server know we're ready to accept the challenges.
281- for ( _, url) in & challenges {
282+ for ( a, url) in & challenges {
283+ info ! ( "Setting challenge ready for {} at {}" , a, url) ;
282284 order. set_challenge_ready ( url) . await . unwrap ( ) ;
283285 }
284286
@@ -287,17 +289,16 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
287289 let mut delay = std:: time:: Duration :: from_millis ( 250 ) ;
288290 let url = authorizations. get ( 0 ) . expect ( "Authorizations is empty" ) ;
289291 let state = loop {
290- actix:: clock:: sleep ( delay) . await ;
291292 let state = order. state ( ) ;
292- if let instant_acme:: OrderStatus :: Ready | instant_acme:: OrderStatus :: Invalid = state. status
293- {
294- info ! ( "order state: {:#?}" , state) ;
293+ info ! ( "Order state: {:#?}" , state) ;
294+ if let OrderStatus :: Ready | OrderStatus :: Invalid | OrderStatus :: Valid = state. status {
295295 break state;
296296 }
297+ order. refresh ( ) . await . unwrap ( ) ;
297298
298299 delay *= 2 ;
299300 tries += 1 ;
300- match tries < 8 {
301+ match tries < 10 {
301302 true => info ! ( "order is not ready, waiting {delay:?}" ) ,
302303 false => {
303304 return Err ( format ! (
@@ -306,6 +307,7 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
306307 . into ( ) ) ;
307308 }
308309 }
310+ actix:: clock:: sleep ( delay) . await ;
309311 } ;
310312
311313 if state. status == OrderStatus :: Invalid {
@@ -319,26 +321,35 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
319321
320322 // If the order is ready, we can provision the certificate.
321323 // Use the rcgen library to create a Certificate Signing Request.
322-
323- let mut params = rcgen:: CertificateParams :: new ( names. clone ( ) ) ;
324+ let mut params = rcgen:: CertificateParams :: new ( names) ;
324325 params. distinguished_name = rcgen:: DistinguishedName :: new ( ) ;
325326 let cert = rcgen:: Certificate :: from_params ( params) . map_err ( |e| e. to_string ( ) ) ?;
326327 let csr = cert. serialize_request_der ( ) . map_err ( |e| e. to_string ( ) ) ?;
327328
328329 // Finalize the order and print certificate chain, private key and account credentials.
329-
330330 order. finalize ( & csr) . await . map_err ( |e| e. to_string ( ) ) ?;
331- let cert_chain_pem = order
332- . certificate ( )
333- . await
334- . map_err ( |e| format ! ( "Error getting certificate {}" , e) ) ?
335- . expect ( "No cert found" ) ;
336- info ! ( "certficate chain:\n \n {}" , cert_chain_pem) ;
337- info ! ( "private key:\n \n {}" , cert. serialize_private_key_pem( ) ) ;
338- // info!(
339- // "account credentials:\n\n{}",
340- // serde_json::to_string_pretty(&account.credentials()).map_err(|e| e.to_string())?
341- // );
331+
332+ let mut tries = 1u8 ;
333+
334+ let cert_chain_pem = loop {
335+ match order. certificate ( ) . await {
336+ Ok ( Some ( cert_chain_pem) ) => {
337+ info ! ( "Certificate ready!" ) ;
338+ break cert_chain_pem;
339+ }
340+ Ok ( None ) => {
341+ if tries > 10 {
342+ return Err ( "Giving up: certificate is still not ready" . into ( ) ) ;
343+ }
344+ tries += 1 ;
345+ info ! ( "Certificate not ready yet..." ) ;
346+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
347+ continue ;
348+ }
349+ Err ( e) => return Err ( format ! ( "Error getting certificate {}" , e) . into ( ) ) ,
350+ }
351+ } ;
352+
342353 write_certs ( config, cert_chain_pem, cert) ?;
343354
344355 if let Some ( hnd) = handle {
0 commit comments