diff --git a/.gitignore b/.gitignore index c13fb1f..132e668 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ dist/ server_hash.txt .aider* +**.pem +proxy/bundle +config.toml +proxy/config.toml diff --git a/Cargo.lock b/Cargo.lock index 983f6af..55da611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2439,6 +2439,12 @@ dependencies = [ "digest", ] +[[package]] +name = "hmac-sha256" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a8575493d277c9092b988c780c94737fb9fd8651a1001e16bee3eccfc1baedb" + [[package]] name = "home" version = "0.5.9" @@ -3403,12 +3409,15 @@ name = "mumble-web2-proxy" version = "0.1.0" dependencies = [ "color-eyre", + "hmac-sha256", "mumble-web2-common", "once_cell", + "rcgen", "rustls", "salvo", "serde", "serde_json", + "time", "tokio", "tokio-rustls", "toml", @@ -4454,6 +4463,19 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.7" @@ -6907,6 +6929,15 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.7.4" diff --git a/config.toml.example b/config.toml.example new file mode 100644 index 0000000..11eca30 --- /dev/null +++ b/config.toml.example @@ -0,0 +1,8 @@ +https_listen_address = "127.0.0.1:4433" +http_listen_address = "127.0.0.1:8080" +mumble_server_url = "[SERVER_URL_HERE]" +gui_path = "target/dx/mumble-web2-gui/release/web/public" + +[gui] +force_proxy = true +proxy_url = "https://127.0.0.1:4433/proxy" diff --git a/proxy/.gitignore b/proxy/.gitignore deleted file mode 100644 index 18c415f..0000000 --- a/proxy/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cert.pem -key.pem -bundle -config.toml diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index 048c5b5..bad728f 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -16,3 +16,6 @@ mumble-web2-common = { workspace = true } salvo = { version = "0.74.2", features = ["quinn", "eyre", "rustls", "serve-static", "logging"] } once_cell = "1.20.2" rustls = { version = "^0.23", features = ["aws_lc_rs"] } +rcgen = "0.13.2" +hmac-sha256 = "1.1.8" +time = "0.3" diff --git a/proxy/config.toml.example b/proxy/config.toml.example deleted file mode 100644 index f5f661c..0000000 --- a/proxy/config.toml.example +++ /dev/null @@ -1,11 +0,0 @@ -https_listen_address = "127.0.0.1:4433" -http_listen_address = "127.0.0.1:8080" -cert_path = "./cert.pem" -key_path = "./key.pem" -mumble_server_url = "voip.ohea.xyz:64738" -gui_path = "../target/dx/mumble-web2-gui/release/web/public" - -[gui] -force_proxy = true -proxy_url = "https://127.0.0.1:4433/proxy" -# cert_hash = [...] diff --git a/proxy/src/main.rs b/proxy/src/main.rs index fd3feaa..3eb4e59 100644 --- a/proxy/src/main.rs +++ b/proxy/src/main.rs @@ -1,6 +1,8 @@ -use color_eyre::eyre::{anyhow, Context, Error, Result}; +use color_eyre::eyre::{anyhow, bail, Context, Result}; +use color_eyre::owo_colors::OwoColorize; use mumble_web2_common::GuiConfig; use once_cell::sync::OnceCell; +use rcgen::date_time_ymd; use salvo::conn::rustls::{Keycert, RustlsConfig}; use salvo::logging::Logger; use salvo::prelude::*; @@ -24,12 +26,18 @@ use tracing::{error, instrument}; use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::EnvFilter; +fn default_cert_alt_names() -> Vec { + vec!["localhost".into()] +} + #[derive(Deserialize)] struct Config { https_listen_address: SocketAddr, http_listen_address: Option, - cert_path: PathBuf, - key_path: PathBuf, + cert_path: Option, + key_path: Option, + #[serde(default = "default_cert_alt_names")] + cert_alt_names: Vec, mumble_server_url: String, mumble_server_address: Option, gui_path: PathBuf, @@ -105,16 +113,42 @@ async fn main() -> Result<()> { .push(Router::with_path("/<*+rest>").get(StaticDir::new(config.gui_path.clone()))) .hoop(Logger::new()); - // Read server certs rustls::crypto::aws_lc_rs::default_provider() .install_default() .map_err(|e| anyhow!("could not install crypto provider {e:?}"))?; - let cert = fs::read(&config.cert_path) - .await - .context(format!("reading cert {}", config.cert_path.display()))?; - let key = fs::read(&config.key_path) - .await - .context(format!("reading key {}", config.key_path.display()))?; + + let (cert, key) = match (&config.cert_path, &config.key_path) { + (None, None) => { + info!("generating self-signed cert"); + + use rcgen::{CertificateParams, KeyPair, PKCS_ECDSA_P256_SHA256}; + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?; + let mut cert_params = CertificateParams::new(config.cert_alt_names.clone())?; + cert_params.not_after = time::OffsetDateTime::now_utc() + time::Duration::days(12); + let cert = cert_params.self_signed(&key_pair)?; + + let hash = hmac_sha256::Hash::hash(cert.der().as_ref()); + { + let mut gui_config = config.gui.lock().unwrap(); + gui_config.cert_hash = Some(hash.into()); + } + + (cert.pem().into(), key_pair.serialize_pem().into()) + } + (Some(cert_path), Some(key_path)) => { + // Read server certs + let cert = fs::read(cert_path) + .await + .context(format!("reading cert {}", cert_path.display()))?; + let key = fs::read(key_path) + .await + .context(format!("reading key {}", key_path.display()))?; + (cert, key) + } + _ => { + bail!("please supply both cert_path and key_path (or neither to generate a self-signed cert)") + } + }; let rustls_config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice())); // Create http listeners