diff --git a/apps/figcraft-server/src/config.rs b/apps/figcraft-server/src/config.rs index 3e951e87..101c7815 100644 --- a/apps/figcraft-server/src/config.rs +++ b/apps/figcraft-server/src/config.rs @@ -135,9 +135,23 @@ impl Config { /// abuse contact, or one whose clients would all count as its proxy). pub fn warnings(&self) -> Vec { let mut out = Vec::new(); + let client_max = NetLimits::default().max_server_message >> 20; + if usize::try_from(self.file_mb()).is_ok_and(|mb| mb >= client_max) { + out.push(format!( + "max_file_mb is {}: the app opens files of up to {} MiB, so a file that large can't be opened", + self.file_mb(), + client_max - 1 + )); + } if !self.open_publish { return out; } + if self.file_mb() > 64 { + out.push(format!( + "open_publish is on with max_file_mb = {}: anyone may send messages that large, and the memory set aside for reading and queueing them grows to eight times it; keep it at 64 or less on a public server", + self.file_mb() + )); + } if self.operator_contact.trim().is_empty() { out.push("open_publish is on but operator_contact is empty: people can't reach you about abuse; set it (and terms_url)".into()); } diff --git a/apps/figcraft-server/src/public_tests.rs b/apps/figcraft-server/src/public_tests.rs index 6403212c..978d9e8e 100644 --- a/apps/figcraft-server/src/public_tests.rs +++ b/apps/figcraft-server/src/public_tests.rs @@ -506,8 +506,21 @@ fn files_above_64_mib_fit_every_limit() { assert!(net.max_reading_total >= net.max_reading_block && net.max_queued_total >= net.max_queued_block); assert!(core.max_message_bytes > file, "open={open_publish}: {}", core.max_message_bytes); } - // A client takes the largest file any server can keep, or as much as a 32-bit target can address - // (computed in u64: `4097 << 20` in a 32-bit usize wraps to 1 MiB). - let client = NetLimits::default().max_server_message as u64; - assert!(client > 4096 << 20 || client == u64::from(u32::MAX), "{client}"); + // A client takes such a file too, but caps what any server may make it buffer at 1 GiB. + assert_eq!(NetLimits::default().max_server_message, 1 << 30); +} + +#[test] +fn large_files_warn_the_operator() { + let public_url = Some("wss://figcraft.example.com/".into()); + let warns = |open_publish, mb| { + Config { open_publish, max_file_mb: Some(mb), public_url: public_url.clone(), ..Config::default() }.warnings().join( + " +", + ) + }; + assert!(!warns(true, 64).contains("max_file_mb"), "{}", warns(true, 64)); + assert!(warns(true, 65).contains("open_publish is on with max_file_mb = 65"), "{}", warns(true, 65)); + assert!(!warns(false, 1023).contains("max_file_mb"), "{}", warns(false, 1023)); + assert!(warns(false, 1024).contains("can't be opened"), "{}", warns(false, 1024)); } diff --git a/crates/collab-net/src/limits.rs b/crates/collab-net/src/limits.rs index 02167770..a0647fa6 100644 --- a/crates/collab-net/src/limits.rs +++ b/crates/collab-net/src/limits.rs @@ -12,10 +12,9 @@ pub struct NetLimits { /// before: its hello. pub max_client_message: usize, pub max_hello: usize, - /// Largest message a client accepts from the host (a welcome carries the whole document): the - /// largest file a `figcraft-server` can be set to keep (`max_file_mb`, at most 4096) and a margin, - /// so a client can open every file a server takes; on a 32-bit target (the browser) as much as - /// `usize` holds. + /// Largest message a client accepts from the host (a welcome carries the whole document): 1 GiB, + /// room for any file up to 1023 MiB and well past the servers' defaults, while a hostile server + /// (any link can name one) can't make the app or a browser tab buffer more than that. pub max_server_message: usize, /// Messages a client may send per second on average, and in a burst; beyond that it is /// disconnected. @@ -64,7 +63,7 @@ impl Default for NetLimits { max_connections: 64, max_client_message: figcraft_collab::Limits::default().max_message_bytes, max_hello: 64 << 10, - max_server_message: usize::try_from(4097u64 << 20).unwrap_or(usize::MAX), + max_server_message: 1 << 30, rate: 100.0, burst: 400.0, hello_timeout: Duration::from_secs(10), diff --git a/docs/server.md b/docs/server.md index 55d784f4..5cbab6a8 100644 --- a/docs/server.md +++ b/docs/server.md @@ -282,7 +282,7 @@ are errors): | `data` | `figcraft-data` | The data directory | | `public_url` | (the listen address) | How links name the server, when people reach it another way (a reverse proxy: `wss://figcraft.example.com/`) | | `max_files` | 1000 | Most files kept | -| `max_file_mb` | 64 (16 when open) | Largest file (its snapshot), in MiB; a welcome carries the whole file, so messages may be as large as a file and 1 MiB (at least 64 MiB on a private server) | +| `max_file_mb` | 64 (16 when open) | Largest file (its snapshot), in MiB; a welcome carries the whole file, so messages may be as large as a file and 1 MiB (at least 64 MiB on a private server). The app opens files of up to 1023 MiB; above 64 with `open_publish` the server warns | | `max_links` | 100 | Most share links per file | | `max_connections` | 512 | Most open connections | | `max_people` | 256 | Most people in one file at once |