use std::sync::Arc;
use certon::{
AcmeIssuer, CertResolver, Config, FileStorage, Http01Solver, KeyType, LETS_ENCRYPT_STAGING,
Result, Storage,
};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
let storage: Arc<dyn Storage> = Arc::new(FileStorage::new("/tmp/certon-http01"));
let http01_solver = Arc::new(Http01Solver::new(80));
let issuer = AcmeIssuer::builder()
.ca(LETS_ENCRYPT_STAGING)
.email("admin@example.com")
.agreed(true)
.storage(storage.clone())
.http01_solver(http01_solver)
.disable_tlsalpn_challenge(true)
.build();
let config = Config::builder()
.storage(storage)
.issuers(vec![Arc::new(issuer)])
.key_type(KeyType::EcdsaP256)
.build();
let domains = vec!["example.com".into()];
println!(
"Obtaining certificate for {:?} via HTTP-01 challenge...",
domains
);
config.manage_sync(&domains).await?;
println!("Certificate obtained successfully!");
let resolver = CertResolver::new(config.cache.clone());
let tls_config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_cert_resolver(Arc::new(resolver));
let acceptor = TlsAcceptor::from(Arc::new(tls_config));
let listener = TcpListener::bind("0.0.0.0:443")
.await
.map_err(|e| certon::Error::Other(format!("failed to bind HTTPS listener: {e}")))?;
println!("HTTPS server listening on 0.0.0.0:443");
let _maintenance = certon::start_maintenance(&config);
loop {
let (stream, peer_addr) = listener
.accept()
.await
.map_err(|e| certon::Error::Other(format!("accept error: {e}")))?;
let acceptor = acceptor.clone();
tokio::spawn(async move {
match acceptor.accept(stream).await {
Ok(mut tls_stream) => {
println!("TLS connection from {peer_addr}");
let mut buf = vec![0u8; 4096];
let _ = tls_stream.read(&mut buf).await;
let response = b"HTTP/1.1 200 OK\r\n\
Content-Type: text/plain\r\n\
Content-Length: 13\r\n\
Connection: close\r\n\
\r\n\
Hello, HTTPS!";
let _ = tls_stream.write_all(response).await;
let _ = tls_stream.shutdown().await;
}
Err(e) => {
eprintln!("TLS handshake failed with {peer_addr}: {e}");
}
}
});
}
}