diff --git a/CHANGELOG.md b/CHANGELOG.md index 9855755..ab2db93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ internet. Ideally `mCaptcha` should automatically generate random salt and rotate periodically, maybe in the next version. +- `master::Master` is moved to `master::embedded::Master` in preparation + for Redis based implementation. + ## 0.1.3 ## Added diff --git a/Cargo.lock b/Cargo.lock index f1e0962..4d7a3ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -618,7 +618,7 @@ checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "libmcaptcha" -version = "0.1.3" +version = "0.1.4" dependencies = [ "actix", "actix-rt", diff --git a/Cargo.toml b/Cargo.toml index 1ea0011..63c3edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libmcaptcha" -version = "0.1.3" +version = "0.1.4" authors = ["realaravinth "] description = "core of mCaptcha captcha system" keywords = ["DDoS", "mcaptcha", "captcha", "pow"] diff --git a/README.md b/README.md index 99b37fd..8dd7580 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,10 @@ If someone wants to hammer your site, they will have to do more work to send requests than your server will have to do to respond to their request. -> **NOTE:** `0.1` is out, expect breaking changes as ergonomics and +> **NOTE:** `0.1.x` is out, expect breaking changes as ergonomics and > performance is improved. Checkout [changelog](./CHANGELOG.md) for -> changes and migration pointers. +> changes and migration pointers. Breaking changes will be frequent +> through `0.1.x`. ## Why use mCaptcha? diff --git a/examples/simple.rs b/examples/simple.rs index 9dbdf1f..ac90910 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,6 @@ use libmcaptcha::{ cache::{messages::VerifyCaptchaResult, HashCache}, - master::{AddSiteBuilder, Master}, + master::embedded::{AddSiteBuilder, Master}, pow::{ConfigBuilder, Work}, system::SystemBuilder, DefenseBuilder, LevelBuilder, MCaptchaBuilder, diff --git a/src/lib.rs b/src/lib.rs index e9e16fe..7c34576 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! ```rust //! use libmcaptcha::{ //! cache::{messages::VerifyCaptchaResult, HashCache}, -//! master::{AddSiteBuilder, Master}, +//! master::embedded::{AddSiteBuilder, Master}, //! pow::{ConfigBuilder, Work}, //! system::SystemBuilder, //! DefenseBuilder, LevelBuilder, MCaptchaBuilder, diff --git a/src/master.rs b/src/master/embedded.rs similarity index 87% rename from src/master.rs rename to src/master/embedded.rs index 28aa02a..6aea1a6 100644 --- a/src/master.rs +++ b/src/master/embedded.rs @@ -17,6 +17,7 @@ */ //! [Master] actor module that manages [MCaptcha] actors use std::collections::BTreeMap; +use std::sync::mpsc::channel; use std::time::Duration; //use actix::clock::sleep; @@ -25,18 +26,21 @@ use actix::dev::*; use derive_builder::Builder; use log::info; +use super::*; use crate::mcaptcha::MCaptcha; /// This Actor manages the [MCaptcha] actors. /// A service can have several [MCaptcha] actors with /// varying [Defense][crate::defense::Defense] configurations /// so a "master" actor is needed to manage them all -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Master { sites: BTreeMap, Addr)>, gc: u64, } +impl Counter for Master {} + impl Master { /// add [MCaptcha] actor to [Master] pub fn add_site(&mut self, details: AddSite) { @@ -82,6 +86,31 @@ impl Actor for Master { } } +impl Handler for Master { + type Result = MessageResult; + + fn handle(&mut self, m: AddVisitor, ctx: &mut Self::Context) -> Self::Result { + let addr = self.get_site(&m.0); + if addr.is_none() { + return MessageResult(None); + } else { + let (tx, rx) = channel(); + let fut = async move { + let config = addr + .unwrap() + .send(crate::mcaptcha::AddVisitor) + .await + .unwrap(); + + tx.send(config).unwrap(); + } + .into_actor(self); + ctx.spawn(fut); + return MessageResult(Some(rx)); + } + } +} + /// Message to get an [MCaptcha] actor from master #[derive(Message)] #[rtype(result = "Option>")] diff --git a/src/master/mod.rs b/src/master/mod.rs new file mode 100644 index 0000000..dbb4b52 --- /dev/null +++ b/src/master/mod.rs @@ -0,0 +1,31 @@ +/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +//! [Master] actor module that manages [MCaptcha] actors +use std::sync::mpsc::Receiver; + +use actix::dev::*; + +pub mod embedded; + +/// Describes actor handler trait impls that are required by a cache implementation +pub trait Counter: actix::Actor + actix::Handler {} + +/// Message to add visitor to an [MCaptcha] actor +#[derive(Message)] +#[rtype(result = "Option>")] +pub struct AddVisitor(pub String); diff --git a/src/system.rs b/src/system.rs index 5774fb6..fcfc754 100644 --- a/src/system.rs +++ b/src/system.rs @@ -23,35 +23,39 @@ use pow_sha256::Config; use crate::cache::messages::*; use crate::cache::Save; use crate::errors::*; -use crate::master::Master; +use crate::master::Counter; use crate::pow::*; /// struct describing various bits of data required for an mCaptcha system #[derive(Clone, Builder)] -pub struct System { - pub master: Addr, +pub struct System { + pub master: Addr, cache: Addr, pow: Config, } -impl System +impl System where T: Save, ::Context: ToEnvelope + ToEnvelope + ToEnvelope + ToEnvelope, + X: Counter, + ::Context: ToEnvelope, { /// utility function to get difficulty factor of site `id` and cache it pub async fn get_pow(&self, id: String) -> Option { - use crate::master::GetSite; - use crate::mcaptcha::AddVisitor; + use crate::master::AddVisitor; - let site_addr = self.master.send(GetSite(id.clone())).await.unwrap(); - if site_addr.is_none() { + let rx = self.master.send(AddVisitor(id.clone())).await.unwrap(); + + if rx.is_none() { return None; } - let mcaptcha = site_addr.unwrap().send(AddVisitor).await.unwrap(); + + let mcaptcha = rx.unwrap().recv().unwrap(); + let pow_config = PoWConfig::new(mcaptcha.difficulty_factor, self.pow.salt.clone()); let cache_msg = CachePoWBuilder::default() @@ -119,12 +123,12 @@ mod tests { use super::System; use super::*; use crate::cache::HashCache; - use crate::master::*; + use crate::master::embedded::*; use crate::mcaptcha::tests::*; const MCAPTCHA_NAME: &str = "batsense.net"; - async fn boostrap_system(gc: u64) -> System { + async fn boostrap_system(gc: u64) -> System { let master = Master::new(gc).start(); let mcaptcha = get_counter().start(); let pow = get_config();