Skip to content

Commit 117b550

Browse files
committed
#192 #574 make openssl optional
1 parent 23f2fe3 commit 117b550

File tree

7 files changed

+209
-191
lines changed

7 files changed

+209
-191
lines changed

server/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ assert_cmd = "2"
102102

103103
[features]
104104
default = ["https", "telemetry"]
105-
https = ["acme-lib", "rustls"]
105+
https = ["rustls"]
106+
https_init = ["acme-lib"]
106107
process-management = ["sysinfo"]
107108
telemetry = ["tracing-opentelemetry", "opentelemetry", "opentelemetry-jaeger"]
108109

server/src/bin.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ mod handlers;
1111
mod helpers;
1212
#[cfg(feature = "https")]
1313
mod https;
14+
#[cfg(feature = "https_init")]
15+
mod https_init;
1416
mod jsonerrors;
1517
#[cfg(feature = "process-management")]
1618
mod process;

server/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl From<tantivy::TantivyError> for AtomicServerError {
166166
}
167167
}
168168

169-
#[cfg(feature = "https")]
169+
#[cfg(feature = "https_init")]
170170
impl From<acme_lib::Error> for AtomicServerError {
171171
fn from(error: acme_lib::Error) -> Self {
172172
AtomicServerError {

server/src/https.rs

Lines changed: 6 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,15 @@
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.
92
use std::{
103
fs::{self, File},
114
io::BufReader,
125
path::PathBuf,
136
};
147

158
use 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

Comments
 (0)