use anyhow::Result; use rustls::internal::pemfile::{certs, rsa_private_keys}; use rustls::{ AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore, ServerConfig, }; use std::fs::File; use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; use structopt::StructOpt; #[derive(StructOpt, Debug)] pub struct Options { /// host to listen on #[structopt(short = "H", long, env = "HOST", default_value = "10.77.2.8")] host: String, /// port to listen on #[structopt(short = "p", long, env = "PORT", default_value = "1965")] port: u16, /// cert file #[structopt(short = "c", long = "cert", env = "CERT_FILE")] cert: PathBuf, /// key file #[structopt(short = "k", long = "key", env = "KEY_FILE")] key: PathBuf, /// server hostname #[structopt( long = "hostname", env = "SERVER_HOSTNAME", default_value = "shachi.wg.akua" )] hostname: String, } fn load_certs(path: &Path) -> io::Result> { certs(&mut BufReader::new(File::open(path)?)) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert")) } fn load_keys(path: &Path) -> io::Result> { rsa_private_keys(&mut BufReader::new(File::open(path)?)) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key")) } pub async fn run(opts: Options) -> Result<()> { let certs = load_certs(&opts.cert)?; let mut keys = load_keys(&opts.key)?; log::info!( "serving gemini://{} on {}:{}", opts.hostname, opts.host, opts.port ); let mut config = ServerConfig::new(AllowAnyAnonymousOrAuthenticatedClient::new( RootCertStore::empty(), )); config .set_single_cert(certs, keys.remove(0)) .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; Ok(()) }