From 895b534207c355bba654d313987d73715726b060 Mon Sep 17 00:00:00 2001 From: alok8bb Date: Mon, 31 Jul 2023 09:31:48 +0530 Subject: [PATCH] add rate limiter with extern crate Signed-off-by: alok8bb --- Cargo.lock | 160 +++++++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 + src/main.rs | 24 +++++++- 3 files changed, 165 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 554a573..eea86a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-extensible-rate-limit" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea990351e38b399d3d1a96eef5e8feba721974a4319f6c66186b05782f6a05b" +dependencies = [ + "actix-web", + "async-trait", + "dashmap", + "futures", + "log", + "once_cell", + "redis", + "thiserror", +] + [[package]] name = "actix-http" version = "3.3.1" @@ -65,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -245,6 +261,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + [[package]] name = "async-trait" version = "0.1.72" @@ -253,7 +275,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -367,6 +389,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "config" version = "0.13.3" @@ -431,6 +467,19 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +dependencies = [ + "cfg-if", + "hashbrown 0.14.0", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "deadpool" version = "0.9.5" @@ -467,6 +516,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "deranged" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" + [[package]] name = "derive_more" version = "0.99.17" @@ -527,9 +582,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -577,6 +632,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -593,6 +663,23 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + [[package]] name = "futures-macro" version = "0.3.28" @@ -601,7 +688,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -622,10 +709,13 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -686,6 +776,12 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hermit-abi" version = "0.3.2" @@ -747,7 +843,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -932,6 +1028,7 @@ dependencies = [ name = "okiba-backend" version = "0.1.0" dependencies = [ + "actix-extensible-rate-limit", "actix-web", "config", "deadpool-postgres", @@ -940,6 +1037,7 @@ dependencies = [ "env_logger", "log", "rand", + "redis", "serde", "serde_json", "tokio-pg-mapper", @@ -960,7 +1058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1034,7 +1132,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1167,6 +1265,27 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redis" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152f3863635cbb76b73bc247845781098302c6c9ad2060e1a9a7de56840346b6" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "combine", + "futures", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "ryu", + "tokio", + "tokio-util", + "url", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1280,22 +1399,22 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.178" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" +checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.178" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" +checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1422,9 +1541,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -1457,15 +1576,16 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] name = "time" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -1480,9 +1600,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index 2b122b3..4cfc0a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +actix-extensible-rate-limit = { version = "0.2.1", features = ["redis"] } actix-web = "4" config = "0.13.3" deadpool-postgres = { version = "0.10.5", features = ["serde"] } @@ -14,6 +15,7 @@ dotenv = "0.15.0" env_logger = "0.10.0" log = "0.4.19" rand = "0.8.5" +redis = { version = "0.21.7", default-features = false, features = ["aio", "tokio-comp", "connection-manager"]} serde = { version = "1.0.178", features = ["derive"] } serde_json = "1.0.104" tokio-pg-mapper = "0.2.0" diff --git a/src/main.rs b/src/main.rs index c28bef9..c3e2f14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,10 @@ mod cfg; mod db; use crate::db::errors::MyError; +use actix_extensible_rate_limit::{ + backend::{redis::RedisBackend, SimpleInputFunctionBuilder}, + RateLimiter, +}; use actix_web::{ get, post, web::{self}, @@ -10,8 +14,12 @@ use cfg::AppConfig; use deadpool_postgres::{Client, Pool}; use dotenv::dotenv; use rand::{distributions::Alphanumeric, Rng}; +use redis::aio::ConnectionManager; use serde_json::json; -use std::str::{self}; +use std::{ + str::{self}, + time::Duration, +}; use tokio_postgres::NoTls; fn generate_endpoint(length: u8) -> String { @@ -69,9 +77,23 @@ async fn main() -> std::io::Result<()> { log::info!("Connecting database"); let pool = config.pg.create_pool(None, NoTls).unwrap(); + let redis_client = + redis::Client::open("redis://127.0.0.1:6379").expect("Couldn't connect to redis database"); + let redis_cm = ConnectionManager::new(redis_client).await.unwrap(); + let redis_backend = RedisBackend::builder(redis_cm).build(); + let server = HttpServer::new(move || { + // 5 requests per 60 seconds + let input = SimpleInputFunctionBuilder::new(Duration::from_secs(60), 5) + .real_ip_key() + .build(); + let middleware = RateLimiter::builder(redis_backend.clone(), input) + .add_headers() + .build(); + App::new() .app_data(web::Data::new(pool.clone())) + .wrap(middleware) .service(new_paste) .service(fetch_paste) })