diff --git a/src/actors/bruteforce_actor.rs b/src/actors/bruteforce_actor.rs index 3ef594d..422f528 100644 --- a/src/actors/bruteforce_actor.rs +++ b/src/actors/bruteforce_actor.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use std::net::IpAddr; -use crate::constants::KEEP_FAILED_LOGIN_ATTEMPTS_FOR; +use actix::{Actor, AsyncContext, Context}; + +use crate::constants::{FAIL_LOGIN_ATTEMPT_CLEANUP_INTERVAL, KEEP_FAILED_LOGIN_ATTEMPTS_FOR}; use crate::utils::time::time; #[derive(Debug, Default)] @@ -41,6 +43,18 @@ impl BruteForceActor { } } +impl Actor for BruteForceActor { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + // Clean up at a regular interval failed attempts + ctx.run_interval(FAIL_LOGIN_ATTEMPT_CLEANUP_INTERVAL, |act, _ctx| { + log::trace!("Cleaning up failed login attempts"); + act.clean_attempts(); + }); + } +} + #[cfg(test)] mod test { use std::net::{IpAddr, Ipv4Addr}; diff --git a/src/constants.rs b/src/constants.rs index 352eb65..7e97ccd 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + /// File in storage containing users list pub const USERS_LIST_FILE: &str = "users.json"; @@ -32,3 +34,4 @@ pub const LOGIN_ROUTE: &str = "/login"; /// Bruteforce protection pub const KEEP_FAILED_LOGIN_ATTEMPTS_FOR: u64 = 3600; pub const MAX_FAILED_LOGIN_ATTEMPTS: u64 = 15; +pub const FAIL_LOGIN_ATTEMPT_CLEANUP_INTERVAL: Duration = Duration::from_secs(60); \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 074a5f2..2df9489 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,12 @@ use actix::Actor; use actix_identity::{CookieIdentityPolicy, IdentityService}; -use actix_web::cookie::time::Duration; +use actix_web::{App, get, HttpServer, web}; use actix_web::cookie::SameSite; +use actix_web::cookie::time::Duration; use actix_web::middleware::Logger; -use actix_web::{get, web, App, HttpServer}; use clap::Parser; +use basic_oidc::actors::bruteforce_actor::BruteForceActor; use basic_oidc::actors::users_actor::UsersActor; use basic_oidc::constants::{ DEFAULT_ADMIN_PASSWORD, DEFAULT_ADMIN_USERNAME, MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, @@ -63,6 +64,7 @@ async fn main() -> std::io::Result<()> { } let users_actor = UsersActor::new(users).start(); + let bruteforce_actor = BruteForceActor::default().start(); log::info!("Server will listen on {}", config.listen_address); let listen_address = config.listen_address.to_string(); @@ -77,6 +79,7 @@ async fn main() -> std::io::Result<()> { App::new() .app_data(web::Data::new(users_actor.clone())) + .app_data(web::Data::new(bruteforce_actor.clone())) .app_data(web::Data::new(config.clone())) .wrap(Logger::default()) .wrap(AuthMiddleware {}) @@ -91,7 +94,7 @@ async fn main() -> std::io::Result<()> { // Logout page .route("/logout", web::get().to(logout_route)) }) - .bind(listen_address)? - .run() - .await + .bind(listen_address)? + .run() + .await }