further simplify proxy config

This commit is contained in:
2025-10-25 18:15:26 -06:00
parent 134e42e69f
commit b8a201911f
11 changed files with 114 additions and 2693 deletions
Generated
+1
View File
@@ -3606,6 +3606,7 @@ dependencies = [
"toml", "toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"url",
] ]
[[package]] [[package]]
+1 -3
View File
@@ -1,9 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize, Default)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct GuiConfig { pub struct ClientConfig {
#[serde(default)]
pub force_proxy: bool,
pub proxy_url: Option<String>, pub proxy_url: Option<String>,
pub cert_hash: Option<Vec<u8>>, pub cert_hash: Option<Vec<u8>>,
} }
+1 -4
View File
@@ -1,8 +1,5 @@
public_url = "https://127.0.0.1:4433"
https_listen_address = "127.0.0.1:4433" https_listen_address = "127.0.0.1:4433"
http_listen_address = "127.0.0.1:8080" http_listen_address = "127.0.0.1:8080"
mumble_server_url = "[SERVER_URL_HERE]" mumble_server_url = "[SERVER_URL_HERE]"
gui_path = "target/dx/mumble-web2-gui/release/web/public" gui_path = "target/dx/mumble-web2-gui/release/web/public"
[gui]
force_proxy = true
proxy_url = "https://127.0.0.1:4433/proxy"
+1 -4
View File
@@ -1,7 +1,4 @@
public_url = "https://127.0.0.1:4433"
https_listen_address = "127.0.0.1:4433" https_listen_address = "127.0.0.1:4433"
http_listen_address = "127.0.0.1:4400" http_listen_address = "127.0.0.1:4400"
mumble_server_url = "127.0.0.1:64738" mumble_server_url = "127.0.0.1:64738"
[gui]
force_proxy = true
proxy_url = "https://127.0.0.1:4433/proxy"
+6 -6
View File
@@ -3,7 +3,7 @@
use base64::{display::Base64Display, prelude::BASE64_URL_SAFE}; use base64::{display::Base64Display, prelude::BASE64_URL_SAFE};
use dioxus::prelude::*; use dioxus::prelude::*;
use mime_guess::Mime; use mime_guess::Mime;
use mumble_web2_common::GuiConfig; use mumble_web2_common::ClientConfig;
use ordermap::OrderSet; use ordermap::OrderSet;
use sir::{css, global_css}; use sir::{css, global_css};
use std::collections::HashMap; use std::collections::HashMap;
@@ -26,7 +26,7 @@ pub enum Command {
Connect { Connect {
address: String, address: String,
username: String, username: String,
config: GuiConfig, config: ClientConfig,
}, },
SendChat { SendChat {
markdown: String, markdown: String,
@@ -437,7 +437,7 @@ pub fn ChatView() -> Element {
//}, //},
#[component] #[component]
pub fn ControlView(config: Resource<GuiConfig>) -> Element { pub fn ControlView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let status = &STATE.status; let status = &STATE.status;
let server = STATE.server.read(); let server = STATE.server.read();
@@ -705,7 +705,7 @@ pub fn ControlView(config: Resource<GuiConfig>) -> Element {
} }
#[component] #[component]
pub fn ServerView(config: Resource<GuiConfig>) -> Element { pub fn ServerView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let server = STATE.server.read(); let server = STATE.server.read();
let Some(&UserState { let Some(&UserState {
@@ -803,7 +803,7 @@ pub fn ServerView(config: Resource<GuiConfig>) -> Element {
} }
#[component] #[component]
pub fn LoginView(config: Resource<GuiConfig>) -> Element { pub fn LoginView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let mut address_input = use_signal(|| None::<String>); let mut address_input = use_signal(|| None::<String>);
@@ -931,7 +931,7 @@ pub fn app() -> Element {
let config = use_resource(|| async move { let config = use_resource(|| async move {
match imp::load_config().await { match imp::load_config().await {
Ok(config) => config, Ok(config) => config,
Err(_) => GuiConfig::default(), Err(_) => ClientConfig::default(),
} }
}); });
+3 -3
View File
@@ -5,7 +5,7 @@ use dioxus::hooks::{UnboundedReceiver, UnboundedSender};
use futures::io::{AsyncRead, AsyncWrite}; use futures::io::{AsyncRead, AsyncWrite};
use mumble_protocol::control::{ClientControlCodec, ControlPacket}; use mumble_protocol::control::{ClientControlCodec, ControlPacket};
use mumble_protocol::Serverbound; use mumble_protocol::Serverbound;
use mumble_web2_common::GuiConfig; use mumble_web2_common::ClientConfig;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use std::sync::Mutex; use std::sync::Mutex;
use std::{fmt, io, sync::Arc}; use std::{fmt, io, sync::Arc};
@@ -188,7 +188,7 @@ pub async fn network_connect(
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
gui_config: &GuiConfig, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
info!("connecting"); info!("connecting");
@@ -228,7 +228,7 @@ pub fn load_username() -> Option<String> {
return None; return None;
} }
pub async fn load_config() -> color_eyre::Result<GuiConfig> { pub async fn load_config() -> color_eyre::Result<ClientConfig> {
color_eyre::eyre::bail!( color_eyre::eyre::bail!(
"there is no config on desktop because desktops cannot be configured as they are tables" "there is no config on desktop because desktops cannot be configured as they are tables"
) )
+12 -7
View File
@@ -7,7 +7,7 @@ use gloo_timers::future::TimeoutFuture;
use mumble_protocol::control::{ClientControlCodec, ControlPacket}; use mumble_protocol::control::{ClientControlCodec, ControlPacket};
use mumble_protocol::voice::{VoicePacket, VoicePacketPayload}; use mumble_protocol::voice::{VoicePacket, VoicePacketPayload};
use mumble_protocol::Serverbound; use mumble_protocol::Serverbound;
use mumble_web2_common::GuiConfig; use mumble_web2_common::ClientConfig;
use reqwest::Url; use reqwest::Url;
use std::time::Duration; use std::time::Duration;
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
@@ -178,8 +178,8 @@ impl AudioPlayer {
// Borrowed from // Borrowed from
// https://github.com/security-union/videocall-rs/blob/main/videocall-client/src/decode/config.rs#L6 // https://github.com/security-union/videocall-rs/blob/main/videocall-client/src/decode/config.rs#L6
fn configure_audio_context() -> AudioContext { fn configure_audio_context() -> AudioContext {
let mut audio_context_options = AudioContextOptions::new(); let audio_context_options = AudioContextOptions::new();
audio_context_options.sample_rate(48000 as f32); audio_context_options.set_sample_rate(48000 as f32);
let audio_context = AudioContext::new_with_context_options(&audio_context_options).unwrap(); let audio_context = AudioContext::new_with_context_options(&audio_context_options).unwrap();
audio_context audio_context
} }
@@ -198,12 +198,14 @@ async fn run_encoder_worklet(
audio_context: &AudioContext, audio_context: &AudioContext,
mut each: impl FnMut(Vec<u8>) + 'static, mut each: impl FnMut(Vec<u8>) + 'static,
) -> Result<AudioWorkletNode, Error> { ) -> Result<AudioWorkletNode, Error> {
let constraints = MediaStreamConstraints::new();
constraints.set_audio(&JsValue::TRUE);
let stream = window() let stream = window()
.unwrap() .unwrap()
.navigator() .navigator()
.media_devices() .media_devices()
.ey()? .ey()?
.get_user_media_with_constraints(MediaStreamConstraints::new().audio(&JsValue::TRUE)) .get_user_media_with_constraints(&constraints)
.ey()? .ey()?
.into_future() .into_future()
.await .await
@@ -309,7 +311,7 @@ pub async fn network_connect(
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
gui_config: &GuiConfig, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
info!("connecting"); info!("connecting");
@@ -388,7 +390,7 @@ pub fn load_username() -> Option<String> {
.ok()? .ok()?
} }
pub async fn load_config() -> color_eyre::Result<GuiConfig> { pub async fn load_config() -> color_eyre::Result<ClientConfig> {
let config_url = match option_env!("MUMBLE_WEB2_GUI_CONFIG_URL") { let config_url = match option_env!("MUMBLE_WEB2_GUI_CONFIG_URL") {
Some(url) => Url::parse(url)?, Some(url) => Url::parse(url)?,
None => { None => {
@@ -399,7 +401,10 @@ pub async fn load_config() -> color_eyre::Result<GuiConfig> {
}; };
info!("loading config from {}", config_url); info!("loading config from {}", config_url);
let config = reqwest::get(config_url).await?.json::<GuiConfig>().await?; let config = reqwest::get(config_url)
.await?
.json::<ClientConfig>()
.await?;
Ok(config) Ok(config)
} }
+1 -1
View File
@@ -20,7 +20,7 @@ use mumble_protocol::voice::VoicePacket;
use mumble_protocol::voice::VoicePacketPayload; use mumble_protocol::voice::VoicePacketPayload;
use mumble_protocol::Clientbound; use mumble_protocol::Clientbound;
use mumble_protocol::Serverbound; use mumble_protocol::Serverbound;
use mumble_web2_common::GuiConfig; use mumble_web2_common::ClientConfig;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::collections::HashMap; use std::collections::HashMap;
-2567
View File
File diff suppressed because it is too large Load Diff
+13 -12
View File
@@ -4,16 +4,16 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
color-eyre = "0.6.3" color-eyre = "^0.6"
serde = { version = "1.0.214", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1.0.132" serde_json = "1"
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "^1.37", features = ["full"] }
tokio-rustls = "^0.26" tokio-rustls = "0.26"
toml = "0.8.19" toml = "0.8"
tracing = { version = "0.1.40", features = ["async-await"] } tracing = { version = "^0.1.40", features = ["async-await"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-subscriber = { version = "^0.3.18", features = ["env-filter"] }
mumble-web2-common = { workspace = true } mumble-web2-common = { workspace = true }
salvo = { version = "0.74.2", features = [ salvo = { version = "^0.74.2", features = [
"quinn", "quinn",
"eyre", "eyre",
"rustls", "rustls",
@@ -22,8 +22,9 @@ salvo = { version = "0.74.2", features = [
"craft", "craft",
"cors", "cors",
] } ] }
once_cell = "1.20.2" once_cell = "^1.20"
rustls = { version = "^0.23", features = ["aws_lc_rs"] } rustls = { version = "^0.23", features = ["aws_lc_rs"] }
rcgen = "0.13.2" rcgen = "^0.13.2"
hmac-sha256 = "1.1.8" hmac-sha256 = "^1.1.8"
time = "0.3" time = "0.3"
url = "2"
+75 -86
View File
@@ -1,6 +1,5 @@
use color_eyre::eyre::{anyhow, bail, Context, Result}; use color_eyre::eyre::{anyhow, bail, Context, Result};
use mumble_web2_common::GuiConfig; use mumble_web2_common::ClientConfig;
use once_cell::sync::OnceCell;
use salvo::conn::rustls::{Keycert, RustlsConfig}; use salvo::conn::rustls::{Keycert, RustlsConfig};
use salvo::cors::{AllowOrigin, Cors}; use salvo::cors::{AllowOrigin, Cors};
use salvo::logging::Logger; use salvo::logging::Logger;
@@ -9,14 +8,14 @@ use salvo::proto::quic::BidiStream;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{SocketAddr, ToSocketAddrs};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use tokio::fs; use tokio::fs;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::pin; use tokio::pin;
use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier};
use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use tokio_rustls::rustls::{ClientConfig, DigitallySignedStruct}; use tokio_rustls::rustls::{ClientConfig as RlsClientConfig, DigitallySignedStruct};
use tokio_rustls::{rustls, TlsConnector}; use tokio_rustls::{rustls, TlsConnector};
use tracing::info; use tracing::info;
use tracing::info_span; use tracing::info_span;
@@ -24,6 +23,7 @@ use tracing::Instrument;
use tracing::{error, instrument}; use tracing::{error, instrument};
use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use url::Url;
fn default_cert_alt_names() -> Vec<String> { fn default_cert_alt_names() -> Vec<String> {
vec!["localhost".into()] vec!["localhost".into()]
@@ -31,6 +31,7 @@ fn default_cert_alt_names() -> Vec<String> {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct Config { struct Config {
public_url: Url,
https_listen_address: SocketAddr, https_listen_address: SocketAddr,
http_listen_address: Option<SocketAddr>, http_listen_address: Option<SocketAddr>,
cert_path: Option<PathBuf>, cert_path: Option<PathBuf>,
@@ -40,12 +41,9 @@ struct Config {
mumble_server_url: String, mumble_server_url: String,
mumble_server_address: Option<SocketAddr>, mumble_server_address: Option<SocketAddr>,
gui_path: Option<PathBuf>, gui_path: Option<PathBuf>,
gui: Mutex<GuiConfig>,
} }
static CONFIG: OnceCell<Config> = OnceCell::new(); fn init_config() -> Result<Config> {
fn init_config() -> Result<()> {
let mut config: Config = toml::from_str( let mut config: Config = toml::from_str(
&std::fs::read_to_string("./config.toml") &std::fs::read_to_string("./config.toml")
.context("reading config.toml (try making a copy of config.toml.example)")?, .context("reading config.toml (try making a copy of config.toml.example)")?,
@@ -63,24 +61,22 @@ fn init_config() -> Result<()> {
config.mumble_server_url config.mumble_server_url
))?; ))?;
config.mumble_server_address = Some(mumble_server_addr); config.mumble_server_address = Some(mumble_server_addr);
CONFIG Ok(config)
.set(config)
.map_err(|_| anyhow!("config already initialized"))?;
Ok(())
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
init_logging(); init_logging();
init_config()?; let server_config = Arc::new(init_config()?);
let config = CONFIG.get().unwrap(); info!("config:\n{}", toml::to_string_pretty(&*server_config)?);
info!("config\n{}", toml::to_string_pretty(&config)?);
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.map_err(|e| anyhow!("could not install crypto provider {e:?}"))?; .map_err(|e| anyhow!("could not install crypto provider {e:?}"))?;
let (cert, key) = match (&config.cert_path, &config.key_path) { let mut client_config = ClientConfig::default();
client_config.proxy_url = Some(server_config.public_url.join("proxy")?.to_string());
let (cert, key) = match (&server_config.cert_path, &server_config.key_path) {
(None, None) => { (None, None) => {
info!("generating self-signed cert"); info!("generating self-signed cert");
@@ -88,17 +84,15 @@ async fn main() -> Result<()> {
let mut dname = rcgen::DistinguishedName::new(); let mut dname = rcgen::DistinguishedName::new();
dname.push(rcgen::DnType::CommonName, "mumble-web self-signed"); dname.push(rcgen::DnType::CommonName, "mumble-web self-signed");
let key_pair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)?; let key_pair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)?;
let mut cert_params = rcgen::CertificateParams::new(config.cert_alt_names.clone())?; let mut cert_params =
rcgen::CertificateParams::new(server_config.cert_alt_names.clone())?;
cert_params.distinguished_name = dname; cert_params.distinguished_name = dname;
cert_params.not_before = time::OffsetDateTime::now_utc(); cert_params.not_before = time::OffsetDateTime::now_utc();
cert_params.not_after = cert_params.not_before + time::Duration::days(12); cert_params.not_after = cert_params.not_before + time::Duration::days(12);
let cert = cert_params.self_signed(&key_pair)?; let cert = cert_params.self_signed(&key_pair)?;
let hash = hmac_sha256::Hash::hash(cert.der().as_ref()); let hash = hmac_sha256::Hash::hash(cert.der().as_ref());
{ client_config.cert_hash = Some(hash.into());
let mut gui_config = config.gui.lock().unwrap();
gui_config.cert_hash = Some(hash.into());
}
(cert.pem().into(), key_pair.serialize_pem().into()) (cert.pem().into(), key_pair.serialize_pem().into())
} }
@@ -118,16 +112,22 @@ async fn main() -> Result<()> {
}; };
let rustls_config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice())); 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)?
);
let config_craft = ConfigCraft { let config_craft = ConfigCraft {
client_config: config.gui.lock().unwrap().clone(), server_config: server_config.clone(),
client_config,
}; };
// Server routing // Server routing
let mut router = Router::new() let mut router = Router::new()
.push(Router::with_path("/proxy").goal(connect_proxy)) .push(Router::with_path("/proxy").goal(config_craft.connect_proxy()))
.push(Router::with_path("/config").get(config_craft.get_config())) .push(Router::with_path("/config").get(config_craft.get_config()))
.hoop(Logger::new()); .hoop(Logger::new());
if let Some(gui_path) = config.gui_path.clone() { if let Some(gui_path) = server_config.gui_path.clone() {
router = router =
router.push(Router::with_path("/").get(StaticFile::new(gui_path.join("index.html")))); router.push(Router::with_path("/").get(StaticFile::new(gui_path.join("index.html"))));
router = router.push(Router::with_path("/<*+rest>").get(StaticDir::new(gui_path))); router = router.push(Router::with_path("/<*+rest>").get(StaticDir::new(gui_path)));
@@ -138,10 +138,10 @@ async fn main() -> Result<()> {
let service = Service::new(router).hoop(cors); let service = Service::new(router).hoop(cors);
// Create http listeners // Create http listeners
let http_listener = config.http_listen_address.map(TcpListener::new); let http_listener = server_config.http_listen_address.map(TcpListener::new);
let https_listener = let https_listener =
TcpListener::new(config.https_listen_address).rustls(rustls_config.clone()); TcpListener::new(server_config.https_listen_address).rustls(rustls_config.clone());
let http3_listener = QuinnListener::new(rustls_config, config.https_listen_address); let http3_listener = QuinnListener::new(rustls_config, server_config.https_listen_address);
// Start server // Start server
match (http_listener, https_listener, http3_listener) { match (http_listener, https_listener, http3_listener) {
@@ -160,76 +160,65 @@ async fn main() -> Result<()> {
#[derive(Clone)] #[derive(Clone)]
pub struct ConfigCraft { pub struct ConfigCraft {
client_config: GuiConfig, server_config: Arc<Config>,
client_config: ClientConfig,
} }
#[craft] #[craft]
impl ConfigCraft { impl ConfigCraft {
#[craft(handler)] #[craft(handler)]
async fn get_config(&self) -> Json<GuiConfig> { async fn get_config(&self) -> Json<ClientConfig> {
Json(self.client_config.clone()) Json(self.client_config.clone())
} }
}
#[handler] #[craft(handler)]
#[instrument] async fn connect_proxy(&self, req: &mut Request, res: &mut Response) {
async fn connect_proxy(req: &mut Request, res: &mut Response) { info!("received proxy request");
info!("received proxy request"); let mumble_server_address = self.server_config.mumble_server_address.unwrap();
let mumble_server_address = CONFIG.get().unwrap().mumble_server_address.unwrap();
let wt = match req.web_transport_mut().await { let wt = match req.web_transport_mut().await {
Ok(wt) => wt, Ok(wt) => wt,
Err(err) => { Err(err) => {
res.status_code(StatusCode::BAD_REQUEST); res.status_code(StatusCode::BAD_REQUEST);
res.render(format!("error with webtransport: {err:?}")); res.render(format!("error with webtransport: {err:?}"));
return; return;
} }
}; };
info!("got webtransport for connection"); info!("got webtransport for connection");
use salvo::webtransport::server::AcceptedBi; use salvo::webtransport::server::AcceptedBi;
let (id, bi) = match wt.accept_bi().await { let (id, bi) = match wt.accept_bi().await {
Ok(Some(AcceptedBi::BidiStream(id, bi))) => (id, bi), Ok(Some(AcceptedBi::BidiStream(id, bi))) => (id, bi),
Ok(Some(AcceptedBi::Request(req, _))) => { Ok(Some(AcceptedBi::Request(req, _))) => {
res.status_code(StatusCode::BAD_REQUEST); res.status_code(StatusCode::BAD_REQUEST);
res.render(format!( res.render(format!(
"expected webtransport stream but got request {req:?}" "expected webtransport stream but got request {req:?}"
)); ));
return; return;
} }
Ok(None) => { Ok(None) => {
res.status_code(StatusCode::BAD_REQUEST); res.status_code(StatusCode::BAD_REQUEST);
res.render(format!("no bidirectional connection requested")); res.render(format!("no bidirectional connection requested"));
return; return;
} }
Err(err) => { Err(err) => {
res.status_code(StatusCode::INTERNAL_SERVER_ERROR); res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
res.render(format!("error with bidirectional connection: {err:?}")); res.render(format!("error with bidirectional connection: {err:?}"));
return; return;
} }
}; };
/* let (outgoing, incoming) = bi.split();
let id = wt.session_id(); let res = tokio::spawn(async move {
let bi = match wt.open_bi(id).await { if let Err(error) = connect_proxy_impl(mumble_server_address, incoming, outgoing).await
Ok(bi) => bi, {
Err(err) => { error!("error connecting proxy {error:?}")
res.status_code(StatusCode::BAD_REQUEST); }
res.render(format!("could not open bidirectional stream: {err:?}")); })
return; .await;
if let Err(err) = res {
error!("crash in connected proxy {err:?}");
} }
};
*/
let (outgoing, incoming) = bi.split();
let res = tokio::spawn(async move {
if let Err(error) = connect_proxy_impl(mumble_server_address, incoming, outgoing).await {
error!("error connecting proxy {error:?}")
}
})
.await;
if let Err(err) = res {
error!("crash in connected proxy {err:?}");
} }
} }
@@ -241,7 +230,7 @@ async fn connect_proxy_impl(
) -> Result<()> { ) -> Result<()> {
info!("connecting to Mumble server..."); info!("connecting to Mumble server...");
let config = ClientConfig::builder() let config = RlsClientConfig::builder()
.dangerous() .dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_custom_certificate_verifier(Arc::new(NoCertificateVerification))
.with_no_client_auth(); .with_no_client_auth();