From aca290f1d0055d6c390e46051c4577d40cd8c652 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 4 Mar 2026 17:42:47 +0100 Subject: [PATCH] Implement TLS support for WebSocket connections in yourchat2. Updated main.rs to handle secure WebSocket connections based on environment variables. Enhanced install-systemd.sh to include a template for environment configuration. Updated README to document new TLS-related environment variables and installation instructions. --- Cargo.lock | 229 +++++++++++++++++++++++++++++++++-- Cargo.toml | 2 + README.md | 8 ++ config/yourchat2.env.example | 21 ++++ install-systemd.sh | 12 +- src/main.rs | 77 +++++++++++- 6 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 config/yourchat2.env.example diff --git a/Cargo.lock b/Cargo.lock index 8396fa1..49f393e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,28 @@ dependencies = [ "syn", ] +[[package]] +name = "aws-lc-rs" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "base64" version = "0.22.1" @@ -71,6 +93,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -90,6 +114,15 @@ dependencies = [ "inout", ] +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -126,6 +159,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "equivalent" version = "1.0.2" @@ -175,6 +214,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-channel" version = "0.3.32" @@ -359,6 +404,16 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.91" @@ -700,6 +755,65 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -964,6 +1078,16 @@ dependencies = [ "whoami", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -1045,6 +1169,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "utf-8" version = "0.7.6" @@ -1224,13 +1354,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.5", ] [[package]] @@ -1242,6 +1381,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows-targets" version = "0.53.5" @@ -1249,58 +1404,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.1" @@ -1402,11 +1605,13 @@ dependencies = [ "futures-util", "hex", "openssl", + "rustls-pemfile", "scrypt", "serde", "serde_json", "tokio", "tokio-postgres", + "tokio-rustls", "tokio-tungstenite", "uuid", ] @@ -1431,6 +1636,12 @@ dependencies = [ "syn", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index 5083a91..27eddf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ tokio-postgres = "0.7" openssl = "0.10" hex = "0.4" scrypt = "0.11" +tokio-rustls = "0.26" +rustls-pemfile = "2" diff --git a/README.md b/README.md index f358ff8..f2bbbac 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ Der Server lauscht danach standardmaessig auf: - `CHAT_WS_ADDR` (default: `0.0.0.0:1235`) - `CHAT_TCP_ADDR` (default: `127.0.0.1:1236`) - `CHAT_UNIX_SOCKET` (optional, z. B. `/run/yourchat2/yourchat2.sock`) +- `CHAT_WS_TLS` (optional, `true` fuer direktes WSS auf `CHAT_WS_ADDR`) +- `CHAT_TLS_CERT_PATH` (Pfad zum PEM-Zertifikat fuer WSS) +- `CHAT_TLS_KEY_PATH` (Pfad zum PEM-Private-Key fuer WSS) - `CHAT_ALLOWED_USERS` (optional, CSV-Liste erlaubter Usernamen, z. B. `alice,bob,carol`) - `CHAT_DB_URL` (optional, PostgreSQL-Connection-String fuer Community-/Chat-User-Checks) - `SECRET_KEY` (benoetigt fuer Entschluesselung verschluesselter Birthdate-Werte aus der DB) @@ -116,6 +119,7 @@ Zusaetzlich gibt es ein Installationsskript `install-systemd.sh`, das: - Arbeitsverzeichnis `/var/lib/yourchat2` erstellt - Environment-Datei unter `/etc/yourchat2/yourchat2.env` anlegt (falls nicht vorhanden) - Service aktiviert und startet +- Standard-Config aus `config/yourchat2.env.example` nach `/etc/yourchat2/yourchat2.env` uebernimmt (falls noch nicht vorhanden) Installation: @@ -132,3 +136,7 @@ Wichtige Variablen fuer produktiven Betrieb: - `CHAT_DB_URL` - `SECRET_KEY` + +Standard-Config-Template im Projekt: + +- `config/yourchat2.env.example` diff --git a/config/yourchat2.env.example b/config/yourchat2.env.example new file mode 100644 index 0000000..ed48cdf --- /dev/null +++ b/config/yourchat2.env.example @@ -0,0 +1,21 @@ +# yourchat2 standard environment configuration + +# Network bindings +CHAT_WS_ADDR=0.0.0.0:1235 +CHAT_TCP_ADDR=127.0.0.1:1236 +# CHAT_UNIX_SOCKET=/run/yourchat2/yourchat2.sock + +# Enable direct WSS on CHAT_WS_ADDR (TLS in daemon itself) +# CHAT_WS_TLS=true +# CHAT_TLS_CERT_PATH=/etc/letsencrypt/live/www.your-part.de/fullchain.pem +# CHAT_TLS_KEY_PATH=/etc/letsencrypt/live/www.your-part.de/privkey.pem + +# Optional user allowlist (comma-separated) +# CHAT_ALLOWED_USERS=alice,bob,carol + +# Database authentication and room metadata +# CHAT_DB_URL=postgres://user:pass@127.0.0.1:5432/yourchat + +# Required if encrypted birthdate values are used in DB +# Must match the key from the legacy system. +# SECRET_KEY=replace-with-real-secret diff --git a/install-systemd.sh b/install-systemd.sh index 0bde697..32e3cda 100755 --- a/install-systemd.sh +++ b/install-systemd.sh @@ -7,6 +7,7 @@ SERVICE_SRC="${PROJECT_DIR}/yourchat2.service" SERVICE_DST="/etc/systemd/system/${SERVICE_NAME}.service" ENV_DIR="/etc/yourchat2" ENV_FILE="${ENV_DIR}/yourchat2.env" +ENV_TEMPLATE="${PROJECT_DIR}/config/yourchat2.env.example" BIN_PATH="${PROJECT_DIR}/target/release/yourchat2" INSTALL_BIN="/usr/local/bin/yourchat2" WORK_DIR="/var/lib/yourchat2" @@ -45,15 +46,20 @@ chown "${BUILD_USER}:${BUILD_USER}" "${WORK_DIR}" echo "[6/7] Ensure environment file ..." if [[ ! -f "${ENV_FILE}" ]]; then - cat > "${ENV_FILE}" <<'EOF' + if [[ -f "${ENV_TEMPLATE}" ]]; then + install -m 0640 "${ENV_TEMPLATE}" "${ENV_FILE}" + else + cat > "${ENV_FILE}" <<'EOF' # yourchat2 environment -# CHAT_WS_ADDR=0.0.0.0:1235 -# CHAT_TCP_ADDR=127.0.0.1:1236 +CHAT_WS_ADDR=0.0.0.0:1235 +CHAT_TCP_ADDR=127.0.0.1:1236 # CHAT_UNIX_SOCKET=/run/yourchat2/yourchat2.sock # CHAT_ALLOWED_USERS=alice,bob # CHAT_DB_URL=postgres://user:pass@host:5432/dbname # SECRET_KEY=replace-with-real-secret EOF + chmod 0640 "${ENV_FILE}" + fi chmod 0640 "${ENV_FILE}" chown root:root "${ENV_FILE}" fi diff --git a/src/main.rs b/src/main.rs index 8e03c36..118edab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,17 @@ use futures_util::{SinkExt, StreamExt}; use std::collections::HashSet; use std::env; +use std::fs::File; +use std::io::BufReader as StdBufReader; use std::path::Path; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader}; use tokio::net::{TcpListener, UnixListener}; use tokio::sync::{mpsc, watch, RwLock}; +use tokio_rustls::TlsAcceptor; +use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; +use tokio_rustls::rustls::ServerConfig as RustlsServerConfig; use tokio_tungstenite::{accept_async, tungstenite::Message}; mod commands; @@ -18,8 +23,14 @@ use types::{ChatState, ClientConn, ServerConfig}; #[tokio::main] async fn main() -> Result<(), Box> { let ws_addr = env::var("CHAT_WS_ADDR").unwrap_or_else(|_| "0.0.0.0:1235".to_string()); + let ws_tls = env_bool("CHAT_WS_TLS"); let tcp_addr = env::var("CHAT_TCP_ADDR").unwrap_or_else(|_| "127.0.0.1:1236".to_string()); let unix_socket = env::var("CHAT_UNIX_SOCKET").ok().filter(|s| !s.trim().is_empty()); + let tls_acceptor = if ws_tls { + Some(Arc::new(load_tls_acceptor_from_env()?)) + } else { + None + }; let state = Arc::new(RwLock::new(ChatState::default())); let db_client = db::connect_db_from_env().await?; @@ -45,11 +56,16 @@ async fn main() -> Result<(), Box> { let (shutdown_tx, shutdown_rx) = watch::channel(false); let ws_listener = TcpListener::bind(&ws_addr).await?; - println!("[yourchat2] listening on ws://{}", ws_addr); + if ws_tls { + println!("[yourchat2] listening on wss://{}", ws_addr); + } else { + println!("[yourchat2] listening on ws://{}", ws_addr); + } let ws_state = Arc::clone(&state); let ws_config = Arc::clone(&config); let ws_next = Arc::clone(&next_client_id); + let ws_tls_acceptor = tls_acceptor.clone(); let mut ws_shutdown_rx = shutdown_rx.clone(); let ws_task = tokio::spawn(async move { loop { @@ -62,13 +78,29 @@ async fn main() -> Result<(), Box> { accepted = ws_listener.accept() => { match accepted { Ok((socket, addr)) => { - println!("[yourchat2] ws client connected: {}", addr); + if ws_tls_acceptor.is_some() { + println!("[yourchat2] wss client connected: {}", addr); + } else { + println!("[yourchat2] ws client connected: {}", addr); + } let state = Arc::clone(&ws_state); let config = Arc::clone(&ws_config); let next = Arc::clone(&ws_next); + let tls_acceptor = ws_tls_acceptor.clone(); let shutdown = ws_shutdown_rx.clone(); tokio::spawn(async move { - if let Err(err) = handle_ws_client(socket, state, config, next, shutdown).await { + if let Some(acceptor) = tls_acceptor { + match acceptor.accept(socket).await { + Ok(tls_stream) => { + if let Err(err) = handle_ws_stream(tls_stream, state, config, next, shutdown).await { + eprintln!("[yourchat2] wss client error: {err}"); + } + } + Err(err) => { + eprintln!("[yourchat2] tls handshake error: {err}"); + } + } + } else if let Err(err) = handle_ws_stream(socket, state, config, next, shutdown).await { eprintln!("[yourchat2] ws client error: {err}"); } }); @@ -249,13 +281,16 @@ where Ok(()) } -async fn handle_ws_client( - socket: tokio::net::TcpStream, +async fn handle_ws_stream( + socket: S, state: Arc>, config: Arc, next_client_id: Arc, mut shutdown_rx: watch::Receiver, -) -> Result<(), Box> { +) -> Result<(), Box> +where + S: AsyncRead + AsyncWrite + Unpin + Send + 'static, +{ let ws_stream = accept_async(socket).await?; let (mut ws_write, mut ws_read) = ws_stream.split(); let client_id = next_client_id.fetch_add(1, Ordering::Relaxed); @@ -319,3 +354,33 @@ async fn handle_ws_client( writer_task.abort(); Ok(()) } + +fn env_bool(name: &str) -> bool { + matches!( + env::var(name).ok().as_deref(), + Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") | Some("on") | Some("ON") + ) +} + +fn load_tls_acceptor_from_env() -> Result> { + let cert_path = env::var("CHAT_TLS_CERT_PATH") + .map_err(|_| "CHAT_WS_TLS=true requires CHAT_TLS_CERT_PATH")?; + let key_path = env::var("CHAT_TLS_KEY_PATH") + .map_err(|_| "CHAT_WS_TLS=true requires CHAT_TLS_KEY_PATH")?; + + let mut cert_reader = StdBufReader::new(File::open(&cert_path)?); + let certs: Vec> = + rustls_pemfile::certs(&mut cert_reader).collect::, _>>()?; + if certs.is_empty() { + return Err("No certificates found in CHAT_TLS_CERT_PATH".into()); + } + + let mut key_reader = StdBufReader::new(File::open(&key_path)?); + let key: PrivateKeyDer<'static> = rustls_pemfile::private_key(&mut key_reader)? + .ok_or("No private key found in CHAT_TLS_KEY_PATH")?; + + let config = RustlsServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key)?; + Ok(TlsAcceptor::from(Arc::new(config))) +}