3
3
//! checks if certificates are not outdated,
4
4
//! persists files on disk.
5
5
6
+ use crate :: errors:: AtomicServerResult ;
7
+ use actix_web:: { dev:: ServerHandle , App , HttpServer } ;
6
8
use std:: {
7
9
fs:: { self , File } ,
8
10
io:: BufReader ,
9
11
path:: PathBuf ,
10
12
} ;
13
+ use tracing:: { info, warn} ;
11
14
12
- use crate :: errors:: AtomicServerResult ;
13
15
/// Create RUSTLS server config from certificates in config dir
14
16
pub fn get_https_config (
15
17
config : & crate :: config:: Config ,
@@ -18,7 +20,6 @@ pub fn get_https_config(
18
20
let https_config = rustls:: ServerConfig :: builder ( )
19
21
. with_safe_defaults ( )
20
22
. with_no_client_auth ( ) ;
21
- // rustls::NoClientAuth::new()
22
23
let cert_file =
23
24
& mut BufReader :: new ( File :: open ( config. cert_path . clone ( ) ) . expect ( "No HTTPS TLS key found." ) ) ;
24
25
let key_file =
@@ -65,7 +66,7 @@ fn set_certs_created_at_file(config: &crate::config::Config) {
65
66
/// Will be true if there are no certs yet.
66
67
pub fn should_renew_certs_check ( config : & crate :: config:: Config ) -> AtomicServerResult < bool > {
67
68
if std:: fs:: File :: open ( & config. cert_path ) . is_err ( ) {
68
- warn ! (
69
+ info ! (
69
70
"No HTTPS certificates found in {:?}, requesting new ones..." ,
70
71
& config. https_path
71
72
) ;
@@ -87,17 +88,12 @@ pub fn should_renew_certs_check(config: &crate::config::Config) -> AtomicServerR
87
88
Ok ( expired)
88
89
}
89
90
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.
97
93
async fn cert_init_server (
98
94
config : & crate :: config:: Config ,
99
95
challenge : & instant_acme:: Challenge ,
100
- key_auth : & KeyAuthorization ,
96
+ key_auth : & instant_acme :: KeyAuthorization ,
101
97
) -> AtomicServerResult < ServerHandle > {
102
98
let address = format ! ( "{}:{}" , config. opts. ip, config. opts. port) ;
103
99
warn ! ( "Server temporarily running in HTTP mode at {}, running Let's Encrypt Certificate initialization..." , address) ;
@@ -117,10 +113,10 @@ async fn cert_init_server(
117
113
challenge_path. push ( "acme-challenge" ) ;
118
114
fs:: create_dir_all ( & challenge_path) ?;
119
115
challenge_path. push ( & challenge. token ) ;
120
- // let challenge_file_content = format!("{}.{}", challenge.token, key_auth.as_str());
121
116
fs:: write ( challenge_path, key_auth. as_str ( ) ) ?;
122
117
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 ( ) ;
124
120
125
121
std:: thread:: spawn ( move || {
126
122
actix_web:: rt:: System :: new ( ) . block_on ( async move {
@@ -153,20 +149,20 @@ async fn cert_init_server(
153
149
& config. opts. domain, & challenge. token
154
150
) ;
155
151
156
- // wait for a few secs
157
152
std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 2 ) ) ;
158
153
info ! ( "Testing availability of {}" , & well_known_url) ;
159
154
160
155
let agent = ureq:: builder ( )
161
156
. timeout ( std:: time:: Duration :: from_secs ( 2 ) )
162
157
. 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
+ } ) ?;
168
164
if resp. status ( ) != 200 {
169
- warn ! ( "Unable to Test local server. Status: {}" , resp. status( ) ) ;
165
+ warn ! ( "Unable to test local server. Status: {}" , resp. status( ) ) ;
170
166
} else {
171
167
info ! ( "Server for HTTP initialization running correctly" ) ;
172
168
}
@@ -175,6 +171,8 @@ async fn cert_init_server(
175
171
176
172
/// Sends a request to LetsEncrypt to create a certificate
177
173
pub async fn request_cert ( config : & crate :: config:: Config ) -> AtomicServerResult < ( ) > {
174
+ use instant_acme:: OrderStatus ;
175
+
178
176
let challenge_type = if config. opts . https_dns {
179
177
info ! ( "Using DNS-01 challenge" ) ;
180
178
instant_acme:: ChallengeType :: Dns01
@@ -188,6 +186,9 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
188
186
// using `Account::from_credentials()`.
189
187
190
188
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
+ ) ;
191
192
instant_acme:: LetsEncrypt :: Staging . url ( )
192
193
} else {
193
194
instant_acme:: LetsEncrypt :: Production . url ( )
@@ -253,7 +254,7 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
253
254
. challenges
254
255
. iter ( )
255
256
. find ( |c| c. r#type == challenge_type)
256
- . ok_or ( "no Dns01 challenge found" ) ?;
257
+ . ok_or ( format ! ( "no {:?} challenge found" , challenge_type ) ) ?;
257
258
258
259
let instant_acme:: Identifier :: Dns ( identifier) = & authz. identifier ;
259
260
@@ -278,7 +279,8 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
278
279
}
279
280
280
281
// 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) ;
282
284
order. set_challenge_ready ( url) . await . unwrap ( ) ;
283
285
}
284
286
@@ -287,17 +289,16 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
287
289
let mut delay = std:: time:: Duration :: from_millis ( 250 ) ;
288
290
let url = authorizations. get ( 0 ) . expect ( "Authorizations is empty" ) ;
289
291
let state = loop {
290
- actix:: clock:: sleep ( delay) . await ;
291
292
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 {
295
295
break state;
296
296
}
297
+ order. refresh ( ) . await . unwrap ( ) ;
297
298
298
299
delay *= 2 ;
299
300
tries += 1 ;
300
- match tries < 8 {
301
+ match tries < 10 {
301
302
true => info ! ( "order is not ready, waiting {delay:?}" ) ,
302
303
false => {
303
304
return Err ( format ! (
@@ -306,6 +307,7 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
306
307
. into ( ) ) ;
307
308
}
308
309
}
310
+ actix:: clock:: sleep ( delay) . await ;
309
311
} ;
310
312
311
313
if state. status == OrderStatus :: Invalid {
@@ -319,26 +321,35 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
319
321
320
322
// If the order is ready, we can provision the certificate.
321
323
// 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) ;
324
325
params. distinguished_name = rcgen:: DistinguishedName :: new ( ) ;
325
326
let cert = rcgen:: Certificate :: from_params ( params) . map_err ( |e| e. to_string ( ) ) ?;
326
327
let csr = cert. serialize_request_der ( ) . map_err ( |e| e. to_string ( ) ) ?;
327
328
328
329
// Finalize the order and print certificate chain, private key and account credentials.
329
-
330
330
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
+
342
353
write_certs ( config, cert_chain_pem, cert) ?;
343
354
344
355
if let Some ( hnd) = handle {
0 commit comments