From d0e44034fe3a6ddfd09e7aebed4ce5289c025121 Mon Sep 17 00:00:00 2001 From: Matthias Ahouansou Date: Tue, 10 Mar 2026 13:24:00 +0000 Subject: [PATCH] defaults for everything except media --- conduit-config/src/rate_limiting.rs | 241 +++++++++++++++++++++++++--- docs/configuration/rate-limiting.md | 2 + xtask/src/generate_docs.rs | 2 +- 3 files changed, 225 insertions(+), 20 deletions(-) diff --git a/conduit-config/src/rate_limiting.rs b/conduit-config/src/rate_limiting.rs index cd562c7c..28e05aca 100644 --- a/conduit-config/src/rate_limiting.rs +++ b/conduit-config/src/rate_limiting.rs @@ -535,7 +535,7 @@ fn nz(int: u64) -> NonZeroU64 { } macro_rules! default_restriction_map { - ($restriction_type:ident; $($restriction:ident, $timeframe:ident, $timeframe_value:expr, $burst_capacity:expr);*) => { + ($restriction_type:ident; $($restriction:ident, $timeframe:ident, $timeframe_value:expr, $burst_capacity:expr;)*) => { HashMap::from_iter([ $(( $restriction_type::$restriction, @@ -603,29 +603,104 @@ impl Config { } pub fn get_preset(preset: ConfigPreset) -> Self { + // The client target map shouldn't really differ between presets, but maybe I'm wrong. + let target_client_map = default_restriction_map!( + ClientRestriction; + + Registration, PerDay, 3, 10; + Login, PerDay, 5, 20; + RegistrationTokenValidity, PerDay, 10, 20; + SendEvent, PerMinute, 15, 60; + Join, PerHour, 5, 30; + Knock, PerHour, 5, 30; + Invite, PerHour, 2, 20; + SendReport, PerDay, 5, 20; + CreateAlias, PerDay, 2, 20; + MediaDownload, PerHour, 30, 100; + MediaCreate, PerMinute, 4, 20; + ); + + // Currently, these values are completely arbitrary, not informed by any sort of + // knowledge. In the future, it would be good to have some sort of analytics to + // determine what some good defaults could be. Maybe getting some percentiles for + // burst_capacity & timeframes used. How we'd tell the difference between power users + // and malicilous attacks, I'm not sure. match preset { - //TODO: finish these ConfigPreset::PrivateSmall => Self { target: ConfigFragment { + client: ConfigFragmentFragment { + map: target_client_map, + media: ClientMediaConfig::todo(), + additional_fields: AuthenticationFailures::new( + Timeframe::PerHour(nz(1)), + nz(20), + ), + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerHour, 10, 10; + Knock, PerHour, 10, 10; + Invite, PerHour, 10, 10; + MediaDownload, PerMinute, 10, 50; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + global: ConfigFragment { client: ConfigFragmentFragment { map: default_restriction_map!( ClientRestriction; - // Registration, PerDay, 10, 20; - // Login, PerHour, 10, 10; - // RegistrationTokenValidity, PerDay, 10, 20 + + Registration, PerDay, 10, 20; + Login, PerHour, 10, 10; + RegistrationTokenValidity, PerDay, 10, 20; + SendEvent, PerSecond, 2, 100; + Join, PerMinute, 1, 30; + Knock, PerMinute, 1, 30; + Invite, PerHour, 10, 20; + SendReport, PerHour, 1, 25; + CreateAlias, PerHour, 5, 20; + MediaDownload, PerMinute, 5, 150; + MediaCreate, PerMinute, 20, 50; ), media: ClientMediaConfig::todo(), + additional_fields: Nothing, + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerMinute, 10, 10; + Knock, PerMinute, 10, 10; + Invite, PerMinute, 10, 10; + MediaDownload, PerSecond, 10, 250; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + }, + ConfigPreset::PrivateMedium => Self { + target: ConfigFragment { + client: ConfigFragmentFragment { + map: target_client_map, + media: ClientMediaConfig::todo(), additional_fields: AuthenticationFailures::new( - Timeframe::PerDay(nz(10)), - nz(40), + Timeframe::PerHour(nz(10)), + nz(20), ), }, federation: ConfigFragmentFragment { map: default_restriction_map!( FederationRestriction; - Join, PerDay, 10, 20; - Knock, PerDay, 10, 20; - Invite, PerDay, 10, 20 + + Join, PerHour, 30, 10; + Knock, PerHour, 30, 10; + Invite, PerHour, 30, 10; + MediaDownload, PerMinute, 100, 50; ), media: FederationMediaConfig::todo(), additional_fields: Nothing, @@ -635,9 +710,78 @@ impl Config { client: ConfigFragmentFragment { map: default_restriction_map!( ClientRestriction; - Registration, PerDay, 10, 20; - Login, PerHour, 10, 10; - RegistrationTokenValidity, PerDay, 10, 20 + + Registration, PerDay, 20, 20; + Login, PerHour, 25, 15; + RegistrationTokenValidity, PerDay, 20, 20; + SendEvent, PerSecond, 10, 100; + Join, PerMinute, 5, 30; + Knock, PerMinute, 5, 30; + Invite, PerMinute, 1, 20; + SendReport, PerHour, 10, 25; + CreateAlias, PerMinute, 1, 50; + MediaDownload, PerSecond, 1, 200; + MediaCreate, PerSecond, 2, 20; + ), + media: ClientMediaConfig::todo(), + additional_fields: Nothing, + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerMinute, 25, 25; + Knock, PerMinute, 25, 25; + Invite, PerMinute, 25, 25; + MediaDownload, PerSecond, 10, 100; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + }, + ConfigPreset::PublicMedium => Self { + target: ConfigFragment { + client: ConfigFragmentFragment { + map: target_client_map, + media: ClientMediaConfig::todo(), + additional_fields: AuthenticationFailures::new( + Timeframe::PerHour(nz(10)), + nz(20), + ), + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerHour, 30, 10; + Knock, PerHour, 30, 10; + Invite, PerHour, 30, 10; + MediaDownload, PerMinute, 100, 50; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + global: ConfigFragment { + client: ConfigFragmentFragment { + map: default_restriction_map!( + ClientRestriction; + + Registration, PerHour, 5, 20; + Login, PerHour, 25, 15; + // Public servers don't have registration tokens, so let's rate limit + // heavily so that if they revert to a private server again, it's a + // reminder to change their preset. + RegistrationTokenValidity, PerDay, 1, 1; + SendEvent, PerSecond, 10, 100; + Join, PerMinute, 5, 30; + Knock, PerMinute, 5, 30; + Invite, PerMinute, 1, 20; + SendReport, PerHour, 10, 25; + CreateAlias, PerMinute, 1, 50; + MediaDownload, PerSecond, 1, 200; + MediaCreate, PerSecond, 2, 20; ), media: ClientMediaConfig::todo(), additional_fields: Nothing, @@ -645,18 +789,77 @@ impl Config { federation: ConfigFragmentFragment { map: default_restriction_map!( FederationRestriction; - // Join, PerDay, 10, 20; - // Knock, PerDay, 10, 20; - // Invite, PerDay, 10, 20 + + Join, PerMinute, 25, 25; + Knock, PerMinute, 25, 25; + Invite, PerMinute, 25, 25; + MediaDownload, PerSecond, 10, 100; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + }, + ConfigPreset::PublicLarge => Self { + target: ConfigFragment { + client: ConfigFragmentFragment { + map: target_client_map, + media: ClientMediaConfig::todo(), + additional_fields: AuthenticationFailures::new( + Timeframe::PerMinute(nz(1)), + nz(20), + ), + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerHour, 90, 30; + Knock, PerHour, 90, 30; + Invite, PerHour, 90, 30; + MediaDownload, PerMinute, 100, 50; + ), + media: FederationMediaConfig::todo(), + additional_fields: Nothing, + }, + }, + global: ConfigFragment { + client: ConfigFragmentFragment { + map: default_restriction_map!( + ClientRestriction; + + Registration, PerMinute, 4, 25; + Login, PerMinute, 10, 25; + // Public servers don't have registration tokens, so let's rate limit + // heavily so that if they revert to a private server again, it's a + // reminder to change their preset. + RegistrationTokenValidity, PerDay, 1, 1; + SendEvent, PerSecond, 100, 50; + Join, PerSecond, 1, 20; + Knock, PerSecond, 1, 20; + Invite, PerMinute, 10, 40; + SendReport, PerMinute, 5, 25; + CreateAlias, PerMinute, 30, 20; + MediaDownload, PerSecond, 25, 200; + MediaCreate, PerSecond, 10, 30; + ), + media: ClientMediaConfig::todo(), + additional_fields: Nothing, + }, + federation: ConfigFragmentFragment { + map: default_restriction_map!( + FederationRestriction; + + Join, PerSecond, 1, 50; + Knock, PerSecond, 1, 50; + Invite, PerSecond, 1, 50; + MediaDownload, PerSecond, 50, 100; ), media: FederationMediaConfig::todo(), additional_fields: Nothing, }, }, }, - ConfigPreset::PrivateMedium => todo!(), - ConfigPreset::PublicMedium => todo!(), - ConfigPreset::PublicLarge => todo!(), } } } diff --git a/docs/configuration/rate-limiting.md b/docs/configuration/rate-limiting.md index bfd9560f..8b414708 100644 --- a/docs/configuration/rate-limiting.md +++ b/docs/configuration/rate-limiting.md @@ -55,6 +55,8 @@ use up the entire global cap, but also prevent potential spam from being spread Restrictions are one-to-many mappings to endpoints that have potential for abuse. Like the overrides mentioned above, they are split into `client` and `federation` restrictions. + + #### Client {{#include ../../target/docs/rate-limiting.md:client-restrictions}} diff --git a/xtask/src/generate_docs.rs b/xtask/src/generate_docs.rs index 2a816366..a4da03ce 100644 --- a/xtask/src/generate_docs.rs +++ b/xtask/src/generate_docs.rs @@ -32,7 +32,7 @@ pub fn run() { let global = preset_config.global.get(&restriction.into()); let target = preset_config.target.get(&restriction.into()); markdown_text.push_str(&format!( - "| {} | {} | {} | {} | {} |\n", + "| `{}` | {} | {} requests | {} | {} requests |\n", variant_to_string(&preset), global.timeframe, global.burst_capacity,