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.
This commit is contained in:
229
Cargo.lock
generated
229
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -14,3 +14,5 @@ tokio-postgres = "0.7"
|
||||
openssl = "0.10"
|
||||
hex = "0.4"
|
||||
scrypt = "0.11"
|
||||
tokio-rustls = "0.26"
|
||||
rustls-pemfile = "2"
|
||||
|
||||
@@ -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`
|
||||
|
||||
21
config/yourchat2.env.example
Normal file
21
config/yourchat2.env.example
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
77
src/main.rs
77
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<dyn std::error::Error + Send + Sync>> {
|
||||
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<dyn std::error::Error + Send + Sync>> {
|
||||
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<dyn std::error::Error + Send + Sync>> {
|
||||
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<S>(
|
||||
socket: S,
|
||||
state: Arc<RwLock<ChatState>>,
|
||||
config: Arc<ServerConfig>,
|
||||
next_client_id: Arc<AtomicU64>,
|
||||
mut shutdown_rx: watch::Receiver<bool>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
|
||||
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<TlsAcceptor, Box<dyn std::error::Error + Send + Sync>> {
|
||||
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<CertificateDer<'static>> =
|
||||
rustls_pemfile::certs(&mut cert_reader).collect::<Result<Vec<_>, _>>()?;
|
||||
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)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user