From 4f1c6326fdef57988decc6c8a056b3e9da73d430 Mon Sep 17 00:00:00 2001 From: spinline Date: Sun, 8 Feb 2026 13:48:04 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20login=20sistemi=20i=C3=A7in=20tower-gov?= =?UTF-8?q?ernor=20ile=20IP=20bazl=C4=B1=20rate=20limit=20eklendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 235 +++++++++++++++++++++++++++++++++++++- backend/Cargo.toml | 2 + backend/src/main.rs | 16 ++- backend/src/rate_limit.rs | 14 +++ 4 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 backend/src/rate_limit.rs diff --git a/Cargo.lock b/Cargo.lock index 8c33a8a..409ef7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,7 @@ dependencies = [ "clap", "dotenvy", "futures", + "governor", "mime_guess", "openssl", "quick-xml", @@ -316,6 +317,7 @@ dependencies = [ "tokio-util", "tower 0.4.13", "tower-http", + "tower_governor", "tracing", "tracing-subscriber", "utoipa", @@ -801,6 +803,20 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.10.0" @@ -1084,6 +1100,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1108,6 +1130,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror 1.0.69", +] + [[package]] name = "frontend" version = "0.1.0" @@ -1214,6 +1246,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -1337,6 +1375,29 @@ dependencies = [ "web-sys", ] +[[package]] +name = "governor" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8" +dependencies = [ + "cfg-if", + "dashmap 6.1.0", + "futures-sink", + "futures-timer", + "futures-util", + "getrandom 0.3.4", + "hashbrown 0.16.1", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.9.2", + "smallvec", + "spinning_top", + "web-time", +] + [[package]] name = "group" version = "0.13.0" @@ -1348,6 +1409,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.0", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.7.1" @@ -1373,7 +1453,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1381,6 +1461,11 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hashlink" @@ -1569,6 +1654,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http 1.4.0", "http-body 1.0.1", "httparse", @@ -1578,6 +1664,20 @@ dependencies = [ "pin-utils", "smallvec", "tokio", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.8.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", ] [[package]] @@ -1600,13 +1700,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "bytes", + "futures-channel", "futures-core", + "futures-util", "http 1.4.0", "http-body 1.0.1", "hyper 1.8.1", + "libc", "pin-project-lite", + "socket2 0.6.2", "tokio", "tower-service", + "tracing", ] [[package]] @@ -2229,6 +2334,18 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2700,6 +2817,21 @@ dependencies = [ "yansi", ] +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + [[package]] name = "quick-xml" version = "0.31.0" @@ -2806,6 +2938,15 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -3196,7 +3337,7 @@ dependencies = [ "bytes", "ciborium", "const_format", - "dashmap", + "dashmap 5.5.3", "futures", "gloo-net 0.6.0", "http 1.4.0", @@ -3375,6 +3516,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.6.0" @@ -3917,6 +4067,35 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "tonic" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a286e33f82f8a1ee2df63f4fa35c0becf4a85a0cb03091a15fd7bf0b402dc94a" +dependencies = [ + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2 0.6.2", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.4.13" @@ -3941,9 +4120,12 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", + "indexmap", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -3988,6 +4170,23 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "tower_governor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44de9b94d849d3c46e06a883d72d408c2de6403367b39df2b1c9d9e7b6736fe6" +dependencies = [ + "axum", + "forwarded-header-value", + "governor", + "http 1.4.0", + "pin-project", + "thiserror 2.0.18", + "tonic", + "tower 0.5.3", + "tracing", +] + [[package]] name = "tracing" version = "0.1.44" @@ -4404,6 +4603,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "whoami" version = "1.6.1" @@ -4414,6 +4623,22 @@ dependencies = [ "wasite", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -4423,6 +4648,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.62.2" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index b3c0ad6..61c13ca 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -39,3 +39,5 @@ axum-extra = { version = "0.10", features = ["cookie"] } rand = "0.8" anyhow = "1.0.101" time = { version = "0.3.47", features = ["serde", "formatting", "parsing"] } +tower_governor = "0.8.0" +governor = "0.10.4" diff --git a/backend/src/main.rs b/backend/src/main.rs index ff9a654..2f46fa9 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -3,6 +3,7 @@ mod diff; mod handlers; #[cfg(feature = "push-notifications")] mod push; +mod rate_limit; mod scgi; mod sse; mod xmlrpc; @@ -25,6 +26,7 @@ use std::sync::Arc; use std::time::Duration; use tokio::sync::{broadcast, watch}; use tower::ServiceBuilder; +use tower_governor::GovernorLayer; use tower_http::{ compression::{CompressionLayer, CompressionLevel}, cors::CorsLayer, @@ -467,7 +469,12 @@ async fn main() { // Setup & Auth Routes .route("/api/setup/status", get(handlers::setup::get_setup_status_handler)) .route("/api/setup", post(handlers::setup::setup_handler)) - .route("/api/auth/login", post(handlers::auth::login_handler)) + .route( + "/api/auth/login", + post(handlers::auth::login_handler).layer(GovernorLayer::new(Arc::new( + rate_limit::get_login_rate_limit_config(), + ))), + ) .route("/api/auth/logout", post(handlers::auth::logout_handler)) .route("/api/auth/check", get(handlers::auth::check_auth_handler)) // App Routes @@ -536,7 +543,12 @@ async fn main() { } }; tracing::info!("Backend listening on {}", addr); - if let Err(e) = axum::serve(listener, app).await { + if let Err(e) = axum::serve( + listener, + app.into_make_service_with_connect_info::(), + ) + .await + { tracing::error!("Server error: {}", e); std::process::exit(1); } diff --git a/backend/src/rate_limit.rs b/backend/src/rate_limit.rs new file mode 100644 index 0000000..91e5979 --- /dev/null +++ b/backend/src/rate_limit.rs @@ -0,0 +1,14 @@ +use governor::clock::QuantaInstant; +use governor::middleware::NoOpMiddleware; +use tower_governor::governor::GovernorConfig; +use tower_governor::governor::GovernorConfigBuilder; +use tower_governor::key_extractor::SmartIpKeyExtractor; + +pub fn get_login_rate_limit_config() -> GovernorConfig> { + GovernorConfigBuilder::default() + .key_extractor(SmartIpKeyExtractor) + .per_second(1) + .burst_size(5) + .finish() + .unwrap() +} \ No newline at end of file