add event_bus_typed
This commit is contained in:
Generated
+133
-3
@@ -189,6 +189,15 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.6.0"
|
||||
@@ -704,6 +713,28 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-server"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ab4a3ec9ea8a657c72d99a03a824af695bd0fb5ec639ccbd9cd3543b41a5f9"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"fs-err",
|
||||
"http 1.5.0",
|
||||
"http-body 1.1.0",
|
||||
"hyper 1.11.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.2.0"
|
||||
@@ -1753,6 +1784,16 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
@@ -1992,6 +2033,25 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.5.0",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
@@ -2191,7 +2251,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.27",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
@@ -2215,6 +2275,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"h2 0.4.19",
|
||||
"http 1.5.0",
|
||||
"http-body 1.1.0",
|
||||
"httparse",
|
||||
@@ -2957,6 +3018,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"axum-server",
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"config",
|
||||
@@ -2967,6 +3029,7 @@ dependencies = [
|
||||
"log",
|
||||
"migration",
|
||||
"parking_lot",
|
||||
"rcgen 0.13.2",
|
||||
"rustrtc",
|
||||
"sea-orm",
|
||||
"serde",
|
||||
@@ -3482,6 +3545,19 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcgen"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
|
||||
dependencies = [
|
||||
"pem 3.0.6",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"time",
|
||||
"yasna 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcgen"
|
||||
version = "0.14.10"
|
||||
@@ -3493,7 +3569,7 @@ dependencies = [
|
||||
"rustls-pki-types",
|
||||
"time",
|
||||
"x509-parser",
|
||||
"yasna",
|
||||
"yasna 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3703,6 +3779,29 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"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.15.1"
|
||||
@@ -3712,6 +3811,18 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustrtc"
|
||||
version = "0.3.138"
|
||||
@@ -3735,7 +3846,7 @@ dependencies = [
|
||||
"p256",
|
||||
"parking_lot",
|
||||
"rand 0.10.2",
|
||||
"rcgen",
|
||||
"rcgen 0.14.10",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1 0.11.0",
|
||||
@@ -4635,6 +4746,16 @@ dependencies = [
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.19"
|
||||
@@ -5446,6 +5567,15 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
|
||||
dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
version = "0.6.0"
|
||||
|
||||
@@ -43,3 +43,5 @@ form_urlencoded = "1.2.2"
|
||||
time = "0.3.55"
|
||||
sha2 = "0.11.0"
|
||||
rustrtc = "0.3.138"
|
||||
axum-server = { version = "0.7", features = ["tls-rustls"] }
|
||||
rcgen = "0.13"
|
||||
|
||||
@@ -8,6 +8,12 @@ tcp_port = 8080
|
||||
# Voice/Video port
|
||||
udp_port = 8080
|
||||
|
||||
# Uncomment for native self-signed HTTPS/WSS. Keep both files between restarts.
|
||||
# [network.tls]
|
||||
# cert_path = "certs/server.pem"
|
||||
# key_path = "certs/server-key.pem"
|
||||
# names = ["localhost", "127.0.0.1"] # include the host clients actually use
|
||||
|
||||
[database]
|
||||
# DSN for database
|
||||
# SQLite
|
||||
|
||||
@@ -51,6 +51,12 @@ tcp_port = 8080
|
||||
# WebRTC ICE/Media UDP multiplexing port
|
||||
udp_port = 8080
|
||||
|
||||
# Optional native HTTPS (omit this section to keep plain HTTP behind a proxy).
|
||||
# [network.tls]
|
||||
# cert_path = "certs/server.pem"
|
||||
# key_path = "certs/server-key.pem"
|
||||
# names = ["localhost", "127.0.0.1"]
|
||||
|
||||
[database]
|
||||
# DSN for database
|
||||
# SQLite
|
||||
@@ -103,6 +109,15 @@ pub struct NetworkConfig {
|
||||
pub hostv6: Option<Ipv6Addr>,
|
||||
pub tcp_port: u16,
|
||||
pub udp_port: u16,
|
||||
#[serde(default)]
|
||||
pub tls: Option<TlsConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct TlsConfig {
|
||||
pub cert_path: std::path::PathBuf,
|
||||
pub key_path: std::path::PathBuf,
|
||||
pub names: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
|
||||
@@ -7,6 +7,7 @@ pub mod metrics;
|
||||
pub mod middleware;
|
||||
pub mod permissions;
|
||||
pub mod server;
|
||||
mod tls;
|
||||
pub mod validation;
|
||||
|
||||
pub use permissions::{RequireChannelPermission, RequireServerPermission};
|
||||
|
||||
+20
-1
@@ -15,12 +15,13 @@ use tower_http::catch_panic::CatchPanicLayer;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use tower_http::trace::TraceLayer;
|
||||
|
||||
use crate::config::NetworkConfig;
|
||||
use crate::config::{NetworkConfig, TlsConfig};
|
||||
use crate::core::AppState;
|
||||
use crate::routes;
|
||||
|
||||
use super::metrics::HttpMetrics;
|
||||
use super::middleware;
|
||||
use super::tls;
|
||||
|
||||
// ── Erreurs ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -66,6 +67,7 @@ pub enum HttpServerError {
|
||||
/// ```
|
||||
pub struct HttpServer {
|
||||
bind_addr: SocketAddr,
|
||||
tls: Option<TlsConfig>,
|
||||
app_state: AppState,
|
||||
metrics: Arc<HttpMetrics>,
|
||||
shutdown_rx: broadcast::Receiver<()>,
|
||||
@@ -87,6 +89,7 @@ impl HttpServer {
|
||||
(
|
||||
Self {
|
||||
bind_addr,
|
||||
tls: network_config.tls.clone(),
|
||||
app_state,
|
||||
metrics,
|
||||
shutdown_rx,
|
||||
@@ -149,6 +152,22 @@ impl HttpServer {
|
||||
// Outermost : intercepte les panics et retourne une 500 propre
|
||||
.layer(CatchPanicLayer::new());
|
||||
|
||||
if let Some(tls_config) = &self.tls {
|
||||
let rustls = tls::load_or_create(tls_config).await?;
|
||||
let handle = axum_server::Handle::new();
|
||||
let shutdown = handle.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = self.shutdown_rx.recv().await;
|
||||
shutdown.graceful_shutdown(Some(std::time::Duration::from_secs(10)));
|
||||
});
|
||||
tracing::info!(addr = %self.bind_addr, "HTTPS server listening");
|
||||
axum_server::bind_rustls(self.bind_addr, rustls)
|
||||
.handle(handle)
|
||||
.serve(app.into_make_service())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let listener =
|
||||
TcpListener::bind(self.bind_addr)
|
||||
.await
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
use crate::config::TlsConfig;
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use std::io;
|
||||
|
||||
pub async fn load_or_create(config: &TlsConfig) -> io::Result<RustlsConfig> {
|
||||
if config.names.is_empty() || config.names.iter().any(|name| name.is_empty()) {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "TLS requires at least one non-empty name"));
|
||||
}
|
||||
if config.cert_path == config.key_path {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "certificate and key paths must differ"));
|
||||
}
|
||||
|
||||
let cert_exists = config.cert_path.exists();
|
||||
let key_exists = config.key_path.exists();
|
||||
if cert_exists != key_exists {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "only one TLS file exists; restore the missing file or remove both to regenerate"));
|
||||
}
|
||||
if !cert_exists {
|
||||
let generated = rcgen::generate_simple_self_signed(config.names.clone())
|
||||
.map_err(io::Error::other)?;
|
||||
for path in [&config.cert_path, &config.key_path] {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
std::fs::write(&config.cert_path, generated.cert.pem())?;
|
||||
let key = generated.key_pair.serialize_pem();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::io::Write;
|
||||
let mut file = std::fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(&config.key_path)?;
|
||||
file.write_all(key.as_bytes())?;
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
std::fs::write(&config.key_path, key)?;
|
||||
tracing::info!(cert = %config.cert_path.display(), "Generated self-signed TLS certificate");
|
||||
}
|
||||
RustlsConfig::from_pem_file(&config.cert_path, &config.key_path).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn certificate_is_reused_and_partial_pair_is_rejected() {
|
||||
let dir = std::env::temp_dir().join(format!("oxspeak-tls-{}", uuid::Uuid::new_v4()));
|
||||
let config = TlsConfig {
|
||||
cert_path: dir.join("cert.pem"), key_path: dir.join("key.pem"),
|
||||
names: vec!["localhost".into()],
|
||||
};
|
||||
load_or_create(&config).await.unwrap();
|
||||
let cert = std::fs::read(&config.cert_path).unwrap();
|
||||
let key = std::fs::read(&config.key_path).unwrap();
|
||||
load_or_create(&config).await.unwrap();
|
||||
assert_eq!(cert, std::fs::read(&config.cert_path).unwrap());
|
||||
assert_eq!(key, std::fs::read(&config.key_path).unwrap());
|
||||
std::fs::remove_file(&config.key_path).unwrap();
|
||||
assert!(load_or_create(&config).await.is_err());
|
||||
std::fs::remove_dir_all(dir).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -341,6 +341,7 @@ mod tests {
|
||||
hostv6: None,
|
||||
tcp_port: 8080,
|
||||
udp_port: 9000,
|
||||
tls: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user