diff --git a/common/src/lib.rs b/common/src/lib.rs index 0d520a5..4821d9a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Deserialize, Serialize, Default)] -pub struct ClientConfig { +pub struct ProxyOverrides { pub proxy_url: Option, pub cert_hash: Option>, pub any_server: bool, diff --git a/docker/Caddyfile b/docker/Caddyfile index 247bd85..449ff36 100644 --- a/docker/Caddyfile +++ b/docker/Caddyfile @@ -1,14 +1,12 @@ localhost:64444 { - tls internal + tls internal - # Proxy /config path to mumble-web2-proxy - reverse_proxy /config http://127.0.0.1:4400 + # Proxy /config path to mumble-web2-proxy + reverse_proxy /overrides http://127.0.0.1:4400 - # Proxy /status path to mumble-web2-proxy - reverse_proxy /status http://127.0.0.1:4400 - - - # Proxy root path to dx-serve - reverse_proxy http://127.0.0.1:8080 + # Proxy /status path to mumble-web2-proxy + reverse_proxy /status http://127.0.0.1:4400 + # Proxy root path to dx-serve + reverse_proxy http://127.0.0.1:8080 } diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 8649f57..fc17325 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -20,7 +20,7 @@ services: # volumes: # - ..:/app # environment: - # - MUMBLE_WEB2_GUI_CONFIG_URL=https://localhost:64444/config + # - MUMBLE_WEB2_PROXY_OVERRIDES_URL=https://localhost:64444/overrides # stdin_open: true # tty: true # command: > diff --git a/gui/src/app.rs b/gui/src/app.rs index a56e647..5de295b 100644 --- a/gui/src/app.rs +++ b/gui/src/app.rs @@ -2,7 +2,7 @@ use dioxus::prelude::*; use mime_guess::Mime; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use ordermap::OrderSet; use std::collections::{HashMap, HashSet}; @@ -23,7 +23,7 @@ pub enum Command { Connect { address: String, username: String, - config: ClientConfig, + config: ProxyOverrides, }, SendChat { markdown: String, @@ -454,7 +454,7 @@ pub fn ChatView() -> Element { } #[component] -pub fn ControlView(config: Resource) -> Element { +pub fn ControlView(overrides: Resource) -> Element { let net: Coroutine = use_coroutine_handle(); let status = &STATE.status; let server = STATE.server.read(); @@ -474,10 +474,10 @@ pub fn ControlView(config: Resource) -> Element { let current_channel_name = server.channels_state.channels[&channel].name.clone(); - let proxy_url = config + let proxy_url = overrides .read_unchecked() .as_ref() - .and_then(|gui_config| gui_config.proxy_url.clone()); + .and_then(|overrides| overrides.proxy_url.clone()); let connecting_color = "yellow"; let connected_color = "oklch(0.55 0.1184 141.35)"; @@ -645,7 +645,7 @@ pub fn ControlView(config: Resource) -> Element { } #[component] -pub fn ServerView(config: Resource) -> Element { +pub fn ServerView(overrides: Resource) -> Element { let net: Coroutine = use_coroutine_handle(); let server = STATE.server.read(); let Some(&UserState { @@ -676,14 +676,14 @@ pub fn ServerView(config: Resource) -> Element { } div { class: "server_control_box", - ControlView { config } + ControlView { overrides } } } ) } #[component] -pub fn LoginView(config: Resource) -> Element { +pub fn LoginView(overrides: Resource) -> Element { let net: Coroutine = use_coroutine_handle(); let last_status = use_signal(|| None::>); @@ -700,7 +700,7 @@ pub fn LoginView(config: Resource) -> Element { if let Some(addr) = address_input() { addr.clone() } else { - config() + overrides() .and_then(|c| c.proxy_url.clone()) .unwrap_or_default() } @@ -712,13 +712,13 @@ pub fn LoginView(config: Resource) -> Element { let do_connect = move |_| { //let _ = set_default_username(&username.read()); let _ = Platform::set_default_username(&username.read()); - if config.read().as_ref().is_some_and(|cfg| cfg.any_server) { + if overrides.read().as_ref().is_some_and(|cfg| cfg.any_server) { Platform::set_default_server(&address.read()); } net.send(Connect { address: address.read().clone(), username: username.read().clone(), - config: config.read().clone().unwrap_or_default(), + config: overrides.read().clone().unwrap_or_default(), }) }; let status = &STATE.status; @@ -763,7 +763,7 @@ pub fn LoginView(config: Resource) -> Element { None => rsx!(), } } - if config.read().as_ref().is_some_and(|cfg| cfg.any_server) { + if overrides.read().as_ref().is_some_and(|cfg| cfg.any_server) { div { label { for: "address-entry", @@ -859,10 +859,10 @@ pub fn app() -> Element { static STYLE: Asset = asset!("/assets/main.scss"); use_coroutine(|rx: UnboundedReceiver| super::network_entrypoint(rx)); - let config = use_resource(|| async move { - match Platform::load_config().await { - Ok(config) => config, - Err(_) => ClientConfig::default(), + let overrides = use_resource(|| async move { + match Platform::load_proxy_overrides().await { + Ok(overrides) => overrides, + Err(_) => ProxyOverrides::default(), } }); @@ -874,8 +874,8 @@ pub fn app() -> Element { document::Link{ rel: "stylesheet", href: STYLE } match *STATE.status.read() { - Connected => rsx!(ServerView { config }), - _ => rsx!(LoginView { config }), + Connected => rsx!(ServerView { overrides }), + _ => rsx!(LoginView { overrides }), } ) } diff --git a/gui/src/imp/connect.rs b/gui/src/imp/connect.rs index e7d3ce7..04a5a61 100644 --- a/gui/src/imp/connect.rs +++ b/gui/src/imp/connect.rs @@ -8,13 +8,13 @@ use tokio::net::TcpStream; use tokio_rustls::rustls; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; -use tokio_rustls::rustls::ClientConfig as RlsClientConfig; +use tokio_rustls::rustls::ClientConfig; use tokio_rustls::rustls::DigitallySignedStruct; use tokio_rustls::TlsConnector; use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _}; use tracing::{info, instrument}; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; #[derive(Debug)] struct NoCertificateVerification; @@ -73,11 +73,11 @@ pub async fn network_connect( address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + overrides: &ProxyOverrides, ) -> Result<(), Error> { info!("connecting"); - let config = RlsClientConfig::builder() + let config = ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_no_client_auth(); diff --git a/gui/src/imp/desktop.rs b/gui/src/imp/desktop.rs index 34a59f8..28a5e9f 100644 --- a/gui/src/imp/desktop.rs +++ b/gui/src/imp/desktop.rs @@ -2,7 +2,7 @@ use crate::app::Command; use color_eyre::eyre::Error; use dioxus::hooks::UnboundedReceiver; use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs}; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use std::collections::HashMap; use std::time::Duration; @@ -16,8 +16,8 @@ impl super::PlatformInterface for DesktopPlatform { tokio::time::sleep(duration).await; } - async fn load_config() -> color_eyre::Result { - Ok(ClientConfig { + async fn load_proxy_overrides() -> color_eyre::Result { + Ok(ProxyOverrides { proxy_url: None, cert_hash: None, any_server: true, @@ -50,9 +50,9 @@ impl super::PlatformInterface for DesktopPlatform { address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + overrides: &ProxyOverrides, ) -> Result<(), Error> { - super::connect::network_connect(address, username, event_rx, gui_config).await + super::connect::network_connect(address, username, event_rx, overrides).await } async fn get_status(client: &reqwest::Client) -> color_eyre::Result { diff --git a/gui/src/imp/mobile.rs b/gui/src/imp/mobile.rs index cac7b86..667a0d8 100644 --- a/gui/src/imp/mobile.rs +++ b/gui/src/imp/mobile.rs @@ -1,8 +1,7 @@ use crate::app::Command; use color_eyre::eyre::Error; use dioxus::hooks::UnboundedReceiver; -use mumble_web2_common::{ClientConfig, ServerStatus}; -use std::future::Future; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use std::time::Duration; /// Mobile platform implementation using Tokio, native audio, and Android permissions. @@ -11,8 +10,8 @@ pub struct MobilePlatform; impl super::PlatformInterface for MobilePlatform { type AudioSystem = super::native_audio::NativeAudioSystem; - async fn load_config() -> color_eyre::Result { - Ok(ClientConfig { + async fn load_proxy_overrides() -> color_eyre::Result { + Ok(ProxyOverrides { proxy_url: None, cert_hash: None, any_server: true, @@ -39,9 +38,9 @@ impl super::PlatformInterface for MobilePlatform { address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + overrides: &ProxyOverrides, ) -> Result<(), Error> { - super::connect::network_connect(address, username, event_rx, gui_config).await + super::connect::network_connect(address, username, event_rx, overrides).await } async fn get_status(client: &reqwest::Client) -> color_eyre::Result { diff --git a/gui/src/imp/mod.rs b/gui/src/imp/mod.rs index a657d31..120f7ce 100644 --- a/gui/src/imp/mod.rs +++ b/gui/src/imp/mod.rs @@ -7,7 +7,7 @@ use crate::{app::Command, effects::AudioProcessor}; use color_eyre::eyre::Error; use dioxus::hooks::UnboundedReceiver; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use std::future::Future; use std::time::Duration; @@ -67,7 +67,7 @@ pub trait PlatformInterface { address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + proxy_overrides: &ProxyOverrides, ) -> impl Future>; /// Get server status (user count, version, etc.). @@ -76,7 +76,7 @@ pub trait PlatformInterface { ) -> impl Future>; /// Load the proxy overrides (proxy URL, cert hash, etc.). - fn load_config() -> impl Future>; + fn load_proxy_overrides() -> impl Future>; /// Load saved username. fn load_username() -> Option; diff --git a/gui/src/imp/stub.rs b/gui/src/imp/stub.rs index d03cd5e..8f68d81 100644 --- a/gui/src/imp/stub.rs +++ b/gui/src/imp/stub.rs @@ -3,7 +3,7 @@ use crate::effects::AudioProcessor; use color_eyre::eyre::Error; use dioxus::hooks::UnboundedReceiver; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use std::future::Future; pub struct StubPlatform; @@ -23,7 +23,7 @@ impl super::PlatformInterface for StubPlatform { _address: String, _username: String, _event_rx: &mut UnboundedReceiver, - _gui_config: &ClientConfig, + _overrides: &ProxyOverrides, ) -> impl Future> { async { panic!("stubbed platform") } } @@ -34,7 +34,7 @@ impl super::PlatformInterface for StubPlatform { async { panic!("stubbed platform") } } - fn load_config() -> impl Future> { + fn load_proxy_overrides() -> impl Future> { async { panic!("stubbed platform") } } diff --git a/gui/src/imp/web.rs b/gui/src/imp/web.rs index 1a55ec4..7fd90ac 100644 --- a/gui/src/imp/web.rs +++ b/gui/src/imp/web.rs @@ -6,7 +6,7 @@ use dioxus::prelude::*; use gloo_timers::future::TimeoutFuture; use js_sys::Float32Array; use mumble_protocol::control::ClientControlCodec; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use reqwest::Url; use std::future::Future; use std::sync::Arc; @@ -89,16 +89,16 @@ impl super::PlatformInterface for WebPlatform { // No-op on web } - async fn load_config() -> color_eyre::Result { - let config_url = match option_env!("MUMBLE_WEB2_GUI_CONFIG_URL") { + async fn load_proxy_overrides() -> color_eyre::Result { + let overrides = match option_env!("MUMBLE_WEB2_PROXY_OVERRIDES_URL") { Some(url) => Url::parse(url)?, - None => absolute_url("config")?, + None => absolute_url("overrides")?, }; - info!("loading config from {}", config_url); + info!("loading config from {}", overrides); - let config = reqwest::get(config_url) + let config = reqwest::get(overrides) .await? - .json::() + .json::() .await?; Ok(config) @@ -133,9 +133,9 @@ impl super::PlatformInterface for WebPlatform { address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + overrides: &ProxyOverrides, ) -> Result<(), Error> { - network_connect(address, username, event_rx, gui_config).await + network_connect(address, username, event_rx, overrides).await } async fn get_status(client: &reqwest::Client) -> color_eyre::Result { @@ -456,7 +456,7 @@ pub async fn network_connect( address: String, username: String, event_rx: &mut UnboundedReceiver, - gui_config: &ClientConfig, + overrides: &ProxyOverrides, ) -> Result<(), Error> { info!("connecting"); @@ -469,7 +469,7 @@ pub async fn network_connect( ) .ey()?; - if let Some(server_hash) = &gui_config.cert_hash { + if let Some(server_hash) = &overrides.cert_hash { let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice()); web_sys::js_sys::Reflect::set(&object, &"value".into(), &hash).ey()?; } diff --git a/proxy/src/main.rs b/proxy/src/main.rs index 53f69db..1f10a43 100644 --- a/proxy/src/main.rs +++ b/proxy/src/main.rs @@ -1,5 +1,5 @@ use color_eyre::eyre::{anyhow, bail, Context, Result}; -use mumble_web2_common::{ClientConfig, ServerStatus}; +use mumble_web2_common::{ProxyOverrides, ServerStatus}; use rand::Rng; use salvo::conn::rustls::{Keycert, RustlsConfig}; use salvo::cors::{AllowOrigin, Cors}; @@ -16,7 +16,7 @@ use tokio::net::TcpStream; use tokio::pin; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; -use tokio_rustls::rustls::{ClientConfig as RlsClientConfig, DigitallySignedStruct}; +use tokio_rustls::rustls::{ClientConfig, DigitallySignedStruct}; use tokio_rustls::{rustls, TlsConnector}; use tracing::info; use tracing::info_span; @@ -77,7 +77,7 @@ async fn main() -> Result<()> { .install_default() .map_err(|e| anyhow!("could not install crypto provider {e:?}"))?; - let mut client_config = ClientConfig { + let mut overrides = ProxyOverrides { proxy_url: match &server_config.proxy_url { Some(url) => Some(url.to_string()), None => None, @@ -102,7 +102,7 @@ async fn main() -> Result<()> { let cert = cert_params.self_signed(&key_pair)?; let hash = hmac_sha256::Hash::hash(cert.der().as_ref()); - client_config.cert_hash = Some(hash.into()); + overrides.cert_hash = Some(hash.into()); (cert.pem().into(), key_pair.serialize_pem().into()) } @@ -122,14 +122,11 @@ async fn main() -> Result<()> { }; let rustls_config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice())); - info!( - "client config:\n{}", - toml::to_string_pretty(&client_config)? - ); + info!("proxy overrides:\n{}", toml::to_string_pretty(&overrides)?); let config_craft = ConfigCraft { server_config: server_config.clone(), - client_config, + overrides, }; let status_craft = StatusCraft { @@ -139,7 +136,7 @@ async fn main() -> Result<()> { // Server routing let mut router = Router::new() .push(Router::with_path("/proxy").goal(config_craft.connect_proxy())) - .push(Router::with_path("/config").get(config_craft.get_config())) + .push(Router::with_path("/overrides").get(config_craft.get_overrides())) .push(Router::with_path("/status").get(status_craft.get_status())) .hoop(Logger::new()); if let Some(gui_path) = server_config.gui_path.clone() { @@ -252,14 +249,14 @@ impl StatusCraft { #[derive(Clone)] pub struct ConfigCraft { server_config: Arc, - client_config: ClientConfig, + overrides: ProxyOverrides, } #[craft] impl ConfigCraft { #[craft(handler)] - async fn get_config(&self) -> Json { - Json(self.client_config.clone()) + async fn get_overrides(&self) -> Json { + Json(self.overrides.clone()) } #[craft(handler)] @@ -320,7 +317,7 @@ async fn connect_proxy_impl( ) -> Result<()> { info!("connecting to Mumble server..."); - let config = RlsClientConfig::builder() + let config = ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_no_client_auth();