From 6933ec28be3dac0dc17cd634c663db3b4818caad Mon Sep 17 00:00:00 2001 From: Doan Luu Duc Tai Date: Fri, 30 Oct 2026 22:36:11 -0500 Subject: Centralize deployment settings in the root environment file Document public domains, ports, upstreams, chat binding, and backup defaults alongside private settings. Validate shared configuration and render Caddy, cgit, and website links from an explicit public allowlist while preserving one installation environment file. --- crates/chat-server/src/main.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'crates/chat-server/src/main.rs') diff --git a/crates/chat-server/src/main.rs b/crates/chat-server/src/main.rs index c17a7f6..cfd3e7a 100644 --- a/crates/chat-server/src/main.rs +++ b/crates/chat-server/src/main.rs @@ -32,8 +32,8 @@ use std::process::ExitCode; struct Arguments { #[arg(long, default_value = ".")] root: PathBuf, - #[arg(long, default_value = "127.0.0.1:9080")] - bind: SocketAddr, + #[arg(long)] + bind: Option, #[arg(long, conflicts_with_all = ["reset_owner", "owner_fingerprint", "snapshot"])] init: bool, #[arg(long, value_name = "FINGERPRINT", conflicts_with_all = ["owner_fingerprint", "snapshot"], help = "Permanently clear the matching owner registration and all chat history after key loss")] @@ -73,7 +73,7 @@ fn initialize(root: &std::path::Path) -> Result<()> { { writeln!(file, "CHAT_ORIGIN=http://127.0.0.1:9080")?; } - Ok(()) + stack_config::initialize_public(root) } async fn run(arguments: Arguments) -> Result<()> { @@ -81,6 +81,8 @@ async fn run(arguments: Arguments) -> Result<()> { if arguments.init { return initialize(&root); } + let configuration = stack_config::Config::load(&root)?; + let bind = arguments.bind.unwrap_or(configuration.chat_bind()?); let data = root.join("var/data/chat"); std::fs::create_dir_all(&data)?; std::fs::set_permissions(&data, std::os::unix::fs::PermissionsExt::from_mode(0o700))?; @@ -99,7 +101,7 @@ async fn run(arguments: Arguments) -> Result<()> { return maintenance::fingerprint(&store); } if let Some(expected) = arguments.reset_owner { - return maintenance::reset(&mut store, &expected, arguments.bind); + return maintenance::reset(&mut store, &expected, bind); } if let Some(destination) = arguments.snapshot { store.snapshot(&destination)?; @@ -110,28 +112,24 @@ async fn run(arguments: Arguments) -> Result<()> { return Ok(()); } ensure!( - arguments.bind.ip().is_loopback(), + bind.ip().is_loopback(), "Experimental server must bind to loopback" ); - let settings = dotenvy::from_path_iter(root.join(".env"))? - .collect::, _>>()?; - let origin = settings - .get("CHAT_ORIGIN") - .context("Run --init to configure chat")?; + let origin = configuration.value("CHAT_ORIGIN")?; ensure!( - origin == &format!("http://{}", arguments.bind), - "This development server requires CHAT_ORIGIN to match its loopback bind address" + origin == format!("http://{bind}"), + "CHAT_ORIGIN must match the loopback CHAT_BIND or --bind address" ); - let setup = settings - .get("CHAT_SETUP_TOKEN") - .context("Missing CHAT_SETUP_TOKEN")?; - let state = service::Service::new(store, origin.clone(), setup.clone()); - let listener = tokio::net::TcpListener::bind(arguments.bind).await?; + let setup = configuration + .value("CHAT_SETUP_TOKEN") + .context("Run --init to configure chat")?; + let state = service::Service::new(store, origin.to_owned(), setup.to_owned()); + let listener = tokio::net::TcpListener::bind(bind).await?; writeln!( std::io::stdout().lock(), "Experimental chat: {origin} (owner setup: /#setup)" )?; - http::serve(listener, state, &root).await + http::serve(listener, state, &root, configuration.public_values(None)?).await } #[tokio::main] -- cgit v1.2.3