1- //! Everything required for setting up HTTPS.
2-
3- use acme_lib:: create_p384_key;
4- use acme_lib:: persist:: FilePersist ;
5- use acme_lib:: { Directory , DirectoryUrl , Error } ;
6- use actix_web:: { App , HttpServer } ;
7-
8- use std:: sync:: mpsc;
1+ //! Everything required for getting HTTPS config from storage.
92use std:: {
103 fs:: { self , File } ,
114 io:: BufReader ,
125 path:: PathBuf ,
136} ;
147
158use crate :: errors:: AtomicServerResult ;
16-
17- /// Starts an HTTP Actix server for HTTPS certificate initialization
18- pub async fn cert_init_server ( config : & crate :: config:: Config ) -> AtomicServerResult < ( ) > {
19- let address = format ! ( "{}:{}" , config. opts. ip, config. opts. port) ;
20- tracing:: warn!( "Server temporarily running in HTTP mode at {}, running Let's Encrypt Certificate initialization..." , address) ;
21-
22- let mut well_known_folder = config. static_path . clone ( ) ;
23- well_known_folder. push ( "well-known" ) ;
24- fs:: create_dir_all ( & well_known_folder) ?;
25-
26- let ( tx, rx) = mpsc:: channel ( ) ;
27-
28- let address_clone = address. clone ( ) ;
29-
30- std:: thread:: spawn ( move || {
31- actix_web:: rt:: System :: new ( ) . block_on ( async move {
32- let init_server = HttpServer :: new ( move || {
33- App :: new ( ) . service (
34- actix_files:: Files :: new ( "/.well-known" , well_known_folder. clone ( ) )
35- . show_files_listing ( ) ,
36- )
37- } ) ;
38-
39- let running_server = init_server. bind ( & address_clone) ?. run ( ) ;
40-
41- tx. send ( running_server. handle ( ) )
42- . expect ( "Error sending handle during HTTPS init" ) ;
43-
44- running_server. await
45- } )
46- } ) ;
47-
48- let handle = rx. recv ( ) . expect ( "Error receiving handle during HTTPS init" ) ;
49-
50- let agent = ureq:: builder ( )
51- . timeout ( std:: time:: Duration :: from_secs ( 2 ) )
52- . build ( ) ;
53-
54- let well_known_url = format ! ( "http://{}/.well-known/" , & config. opts. domain) ;
55- tracing:: info!( "Testing availability of {}" , & well_known_url) ;
56- let resp = agent
57- . get ( & well_known_url)
58- . call ( )
59- . expect ( "Unable to send request for Let's Encrypt initialization" ) ;
60- if resp. status ( ) != 200 {
61- return Err (
62- "Server for HTTP initialization not available, returning a non-200 status code" . into ( ) ,
63- ) ;
64- } else {
65- tracing:: info!( "Server for HTTP initialization running correctly" ) ;
66- }
67-
68- crate :: https:: request_cert ( config) . map_err ( |e| format ! ( "Certification init failed: {}" , e) ) ?;
69- tracing:: warn!( "HTTPS TLS Cert init sucesful! Stopping HTTP server, starting HTTPS..." ) ;
70- handle. stop ( true ) . await ;
71- Ok ( ( ) )
72- }
73-
74- /// Writes keys to disk using LetsEncrypt
75- pub fn request_cert ( config : & crate :: config:: Config ) -> Result < ( ) , Error > {
76- // Use DirectoryUrl::LetsEncrypStaging for dev/testing.
77- let url = if config. opts . development {
78- DirectoryUrl :: LetsEncryptStaging
79- } else {
80- DirectoryUrl :: LetsEncrypt
81- } ;
82-
83- fs:: create_dir_all ( PathBuf :: from ( & config. https_path ) ) ?;
84-
85- // Save/load keys and certificates to current dir.
86- let persist = FilePersist :: new ( & config. https_path ) ;
87-
88- // Create a directory entrypoint.
89- let dir = Directory :: from_url ( persist, url) ?;
90-
91- // Reads the private account key from persistence, or
92- // creates a new one before accessing the API to establish
93- // that it's there.
94- let email = config
95- . opts
96- . email
97- . clone ( )
98- . expect ( "ATOMIC_EMAIL must be set for HTTPS init" ) ;
99- tracing:: info!( "Requesting Let's Encrypt account with {}" , email) ;
100- let acc = dir. account ( & email) ?;
101-
102- // Order a new TLS certificate for a domain.
103- let mut ord_new = acc. new_order ( & config. opts . domain , & [ ] ) ?;
104-
105- // If the ownership of the domain(s) have already been
106- // authorized in a previous order, you might be able to
107- // skip validation. The ACME API provider decides.
108- let ord_csr = loop {
109- // are we done?
110- if let Some ( ord_csr) = ord_new. confirm_validations ( ) {
111- break ord_csr;
112- }
113-
114- // Get the possible authorizations (for a single domain
115- // this will only be one element).
116- let auths = ord_new. authorizations ( ) ?;
117-
118- // For HTTP, the challenge is a text file that needs to
119- // be placed in your web server's root:
120- //
121- // /var/www/.well-known/acme-challenge/<token>
122- //
123- // The important thing is that it's accessible over the
124- // web for the domain(s) you are trying to get a
125- // certificate for:
126- //
127- // http://mydomain.io/.well-known/acme-challenge/<token>
128- let chall = auths[ 0 ] . http_challenge ( ) ;
129-
130- // The token is the filename.
131- let token = chall. http_token ( ) ;
132-
133- let formatted_path = format ! ( "well-known/acme-challenge/{}" , token) ;
134- let mut challenge_path = config. static_path . clone ( ) ;
135- challenge_path. push ( formatted_path) ;
136-
137- // The proof is the contents of the file
138- let proof = chall. http_proof ( ) ;
139-
140- tracing:: info!( "Writing ACME challange to {:?}" , challenge_path) ;
141-
142- fs:: create_dir_all (
143- PathBuf :: from ( & challenge_path)
144- . parent ( )
145- . expect ( "Could not find parent folder" ) ,
146- )
147- . expect ( "Unable to create dirs" ) ;
148-
149- fs:: write ( challenge_path, proof) . expect ( "Unable to write file" ) ;
150-
151- // Here you must do "something" to place
152- // the file/contents in the correct place.
153- // update_my_web_server(&path, &proof);
154-
155- // After the file is accessible from the web, the calls
156- // this to tell the ACME API to start checking the
157- // existence of the proof.
158- //
159- // The order at ACME will change status to either
160- // confirm ownership of the domain, or fail due to the
161- // not finding the proof. To see the change, we poll
162- // the API with 5000 milliseconds wait between.
163- chall. validate ( 5000 ) ?;
164-
165- // Update the state against the ACME API.
166- ord_new. refresh ( ) ?;
167- } ;
168-
169- // Ownership is proven. Create a private key for
170- // the certificate. These are provided for convenience, you
171- // can provide your own keypair instead if you want.
172- let pkey_pri = create_p384_key ( ) ;
173-
174- // Submit the CSR. This causes the ACME provider to enter a
175- // state of "processing" that must be polled until the
176- // certificate is either issued or rejected. Again we poll
177- // for the status change.
178- let ord_cert = ord_csr. finalize_pkey ( pkey_pri, 5000 ) ?;
179-
180- // Now download the certificate. Also stores the cert in
181- // the persistence.
182- tracing:: info!( "Downloading certificate..." ) ;
183- let cert = ord_cert. download_and_save_cert ( ) ?;
184-
185- fs:: write ( & config. cert_path , cert. certificate ( ) ) . expect ( "Unable to write file" ) ;
186- fs:: write ( & config. key_path , cert. private_key ( ) ) . expect ( "Unable to write file" ) ;
187- set_certs_created_at_file ( config) ;
188- tracing:: info!( "HTTPS init Success!" ) ;
189- Ok ( ( ) )
190- }
191-
1929// RUSTLS
193- pub fn get_https_config ( config : & crate :: config:: Config ) -> Result < rustls:: ServerConfig , Error > {
10+ pub fn get_https_config (
11+ config : & crate :: config:: Config ,
12+ ) -> AtomicServerResult < rustls:: ServerConfig > {
19413 use rustls_pemfile:: { certs, pkcs8_private_keys} ;
19514 let https_config = rustls:: ServerConfig :: builder ( )
19615 . with_safe_defaults ( )
@@ -215,7 +34,7 @@ pub fn get_https_config(config: &crate::config::Config) -> Result<rustls::Server
21534 . expect ( "Unable to create HTTPS config from certificates" ) )
21635}
21736
218- fn certs_created_at_path ( config : & crate :: config:: Config ) -> PathBuf {
37+ pub fn certs_created_at_path ( config : & crate :: config:: Config ) -> PathBuf {
21938 // ~/.config/atomic/https
22039 let mut path = config
22140 . cert_path
@@ -232,7 +51,7 @@ fn certs_created_at_path(config: &crate::config::Config) -> PathBuf {
23251}
23352
23453/// Adds a file to the .https folder to indicate age of certificates
235- fn set_certs_created_at_file ( config : & crate :: config:: Config ) {
54+ pub fn set_certs_created_at_file ( config : & crate :: config:: Config ) {
23655 let now_string = chrono:: Utc :: now ( ) ;
23756 let path = certs_created_at_path ( config) ;
23857 fs:: write ( & path, now_string. to_string ( ) )
0 commit comments