counter is now a wrapper over mcaptcha
This commit is contained in:
parent
cc88c69fc6
commit
13b38c5b6c
8 changed files with 508 additions and 125 deletions
|
@ -15,11 +15,8 @@
|
||||||
- `master::Master` is moved to `master::embedded::master` in preparation
|
- `master::Master` is moved to `master::embedded::master` in preparation
|
||||||
for Redis based implementation.
|
for Redis based implementation.
|
||||||
|
|
||||||
- `crate::mcaptcha` is moved to `master::embedded::counter` in preparation
|
|
||||||
for Redis based implementation.
|
|
||||||
|
|
||||||
- `AddSite` message for `Master` now requires an instance of
|
- `AddSite` message for `Master` now requires an instance of
|
||||||
`crate::master::MCaptcha`. In the case of
|
`crate::mcaptcha::MCaptcha`. In the case of
|
||||||
`crate::master::embedded::master`, it automatically starts `Counter`
|
`crate::master::embedded::master`, it automatically starts `Counter`
|
||||||
actor.
|
actor.
|
||||||
|
|
||||||
|
@ -54,7 +51,7 @@
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- actix upgraded to `0.11`
|
- `actix` upgraded to `0.11`
|
||||||
|
|
||||||
## 0.1.1
|
## 0.1.1
|
||||||
|
|
||||||
|
|
143
Cargo.lock
generated
143
Cargo.lock
generated
|
@ -9,7 +9,7 @@ dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix_derive",
|
"actix_derive",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes 0.5.6",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
@ -19,8 +19,8 @@ dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio 0.2.25",
|
||||||
"tokio-util",
|
"tokio-util 0.3.1",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
"trust-dns-resolver",
|
"trust-dns-resolver",
|
||||||
]
|
]
|
||||||
|
@ -47,7 +47,7 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio 0.2.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -150,6 +150,12 @@ version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -162,6 +168,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "combine"
|
||||||
|
version = "4.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 1.0.1",
|
||||||
|
"futures-util",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite 0.2.6",
|
||||||
|
"tokio 1.6.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -180,6 +199,12 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
|
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc16"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "338089f42c427b86394a5ee60ff321da23a5c89c9d89514c829687b26359fcff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -349,6 +374,12 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dtoa"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enum-as-inner"
|
name = "enum-as-inner"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -628,6 +659,7 @@ dependencies = [
|
||||||
"pow_sha256",
|
"pow_sha256",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rand 0.8.3",
|
"rand 0.8.3",
|
||||||
|
"redis",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
@ -702,12 +734,25 @@ dependencies = [
|
||||||
"kernel32-sys",
|
"kernel32-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"miow",
|
"miow 0.2.2",
|
||||||
"net2",
|
"net2",
|
||||||
"slab",
|
"slab",
|
||||||
"winapi 0.2.8",
|
"winapi 0.2.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.7.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"miow 0.3.7",
|
||||||
|
"ntapi",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio-uds"
|
name = "mio-uds"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
@ -716,7 +761,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iovec",
|
"iovec",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio 0.6.23",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -731,6 +776,15 @@ dependencies = [
|
||||||
"ws2_32-sys",
|
"ws2_32-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miow"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net2"
|
name = "net2"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
|
@ -742,6 +796,15 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
@ -965,6 +1028,28 @@ dependencies = [
|
||||||
"rand_core 0.6.2",
|
"rand_core 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redis"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a32cb439c4e89c1e6415e5b3b23d9d8cc6dc1bf5a8cade19adbd5418de803be"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes 1.0.1",
|
||||||
|
"combine",
|
||||||
|
"crc16",
|
||||||
|
"dtoa",
|
||||||
|
"futures-util",
|
||||||
|
"itoa",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite 0.2.6",
|
||||||
|
"rand 0.8.3",
|
||||||
|
"sha1",
|
||||||
|
"tokio 1.6.1",
|
||||||
|
"tokio-util 0.6.7",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -1044,6 +1129,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
@ -1171,14 +1262,14 @@ version = "0.2.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 0.5.6",
|
||||||
"fnv",
|
"fnv",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"iovec",
|
"iovec",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mio",
|
"mio 0.6.23",
|
||||||
"mio-uds",
|
"mio-uds",
|
||||||
"pin-project-lite 0.1.12",
|
"pin-project-lite 0.1.12",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
@ -1186,19 +1277,47 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bytes 1.0.1",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio 0.7.11",
|
||||||
|
"pin-project-lite 0.2.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 0.5.6",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite 0.1.12",
|
"pin-project-lite 0.1.12",
|
||||||
"tokio",
|
"tokio 0.2.25",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.6.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 1.0.1",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"log",
|
||||||
|
"pin-project-lite 0.2.6",
|
||||||
|
"tokio 1.6.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1217,7 +1336,7 @@ dependencies = [
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio 0.2.25",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1236,7 +1355,7 @@ dependencies = [
|
||||||
"resolv-conf",
|
"resolv-conf",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio 0.2.25",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ derive_more = "0.99"
|
||||||
|
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
pow_sha256 = { version = "0.2.1", git = "https://github.com/mcaptcha/pow_sha256" }
|
pow_sha256 = { version = "0.2.1", git = "https://github.com/mcaptcha/pow_sha256" }
|
||||||
|
redis = { version = "0.20.1", features = ["tokio-comp","aio", "cluster"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "1"
|
actix-rt = "1"
|
||||||
|
|
|
@ -189,6 +189,7 @@ pub mod master;
|
||||||
|
|
||||||
/// message datatypes to interact with [MCaptcha] actor
|
/// message datatypes to interact with [MCaptcha] actor
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
pub mod mcaptcha;
|
||||||
pub mod pow;
|
pub mod pow;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -197,4 +198,4 @@ pub use crate::cache::hashcache::HashCache;
|
||||||
|
|
||||||
pub use defense::{Defense, DefenseBuilder, LevelBuilder};
|
pub use defense::{Defense, DefenseBuilder, LevelBuilder};
|
||||||
pub use master::embedded::counter::Counter;
|
pub use master::embedded::counter::Counter;
|
||||||
pub use master::MCaptchaBuilder;
|
pub use mcaptcha::{MCaptcha, MCaptchaBuilder};
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use libmcaptcha::{
|
//! use libmcaptcha::{
|
||||||
//! master::embedded::counter::{Counter, AddVisitor},
|
//! master::embedded::counter::{Counter, AddVisitor},
|
||||||
//! master::MCaptchaBuilder,
|
//! MCaptchaBuilder,
|
||||||
//! cache::HashCache,
|
//! cache::HashCache,
|
||||||
//! LevelBuilder,
|
//! LevelBuilder,
|
||||||
//! DefenseBuilder
|
//! DefenseBuilder
|
||||||
|
@ -86,56 +86,49 @@ use std::time::Duration;
|
||||||
use actix::dev::*;
|
use actix::dev::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::master::MCaptcha;
|
use crate::master::AddVisitorResult;
|
||||||
use crate::{defense::Defense, master::AddVisitorResult};
|
use crate::mcaptcha::MCaptcha;
|
||||||
|
|
||||||
/// This struct represents the mCaptcha state and is used
|
/// This struct represents the mCaptcha state and is used
|
||||||
/// to configure leaky-bucket lifetime and manage defense
|
/// to configure leaky-bucket lifetime and manage defense
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub struct Counter {
|
pub struct Counter(MCaptcha);
|
||||||
visitor_threshold: u32,
|
|
||||||
defense: Defense,
|
|
||||||
duration: u64,
|
|
||||||
}
|
|
||||||
impl From<MCaptcha> for Counter {
|
impl From<MCaptcha> for Counter {
|
||||||
fn from(m: MCaptcha) -> Counter {
|
fn from(m: MCaptcha) -> Counter {
|
||||||
let m = Counter {
|
Counter(m)
|
||||||
duration: m.duration,
|
|
||||||
defense: m.defense,
|
|
||||||
visitor_threshold: m.visitor_threshold,
|
|
||||||
};
|
|
||||||
m
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Counter {
|
// impl Counter {
|
||||||
/// increments the visitor count by one
|
// /// increments the visitor count by one
|
||||||
pub fn add_visitor(&mut self) {
|
// pub fn add_visitor(&mut self) {
|
||||||
self.visitor_threshold += 1;
|
// self.visitor_threshold += 1;
|
||||||
if self.visitor_threshold > self.defense.visitor_threshold() {
|
// if self.visitor_threshold > self.defense.visitor_threshold() {
|
||||||
self.defense.tighten_up();
|
// self.defense.tighten_up();
|
||||||
} else {
|
// } else {
|
||||||
self.defense.loosen_up();
|
// self.defense.loosen_up();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// /// decrements the visitor count by one
|
||||||
|
// pub fn decrement_visitor(&mut self) {
|
||||||
|
// if self.visitor_threshold > 0 {
|
||||||
|
// self.visitor_threshold -= 1;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// get current difficulty factor
|
||||||
|
// pub fn get_difficulty(&self) -> u32 {
|
||||||
|
// self.defense.get_difficulty()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// get [Counter]'s lifetime
|
||||||
|
// pub fn get_duration(&self) -> u64 {
|
||||||
|
// self.duration
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/// decrements the visitor count by one
|
|
||||||
pub fn decrement_visitor(&mut self) {
|
|
||||||
if self.visitor_threshold > 0 {
|
|
||||||
self.visitor_threshold -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get current difficulty factor
|
|
||||||
pub fn get_difficulty(&self) -> u32 {
|
|
||||||
self.defense.get_difficulty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get [Counter]'s lifetime
|
|
||||||
pub fn get_duration(&self) -> u64 {
|
|
||||||
self.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Actor for Counter {
|
impl Actor for Counter {
|
||||||
type Context = Context<Self>;
|
type Context = Context<Self>;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +141,7 @@ struct DeleteVisitor;
|
||||||
impl Handler<DeleteVisitor> for Counter {
|
impl Handler<DeleteVisitor> for Counter {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
fn handle(&mut self, _msg: DeleteVisitor, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, _msg: DeleteVisitor, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
self.decrement_visitor();
|
self.0.decrement_visitor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +154,8 @@ pub struct AddVisitor;
|
||||||
impl AddVisitorResult {
|
impl AddVisitorResult {
|
||||||
fn new(m: &Counter) -> Self {
|
fn new(m: &Counter) -> Self {
|
||||||
AddVisitorResult {
|
AddVisitorResult {
|
||||||
duration: m.get_duration(),
|
duration: m.0.get_duration(),
|
||||||
difficulty_factor: m.get_difficulty(),
|
difficulty_factor: m.0.get_difficulty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +167,7 @@ impl Handler<AddVisitor> for Counter {
|
||||||
let addr = ctx.address();
|
let addr = ctx.address();
|
||||||
use actix::clock::delay_for;
|
use actix::clock::delay_for;
|
||||||
|
|
||||||
let duration: Duration = Duration::new(self.duration.clone(), 0);
|
let duration: Duration = Duration::new(self.0.get_duration(), 0);
|
||||||
let wait_for = async move {
|
let wait_for = async move {
|
||||||
//sleep(duration).await;
|
//sleep(duration).await;
|
||||||
delay_for(duration).await;
|
delay_for(duration).await;
|
||||||
|
@ -183,7 +176,7 @@ impl Handler<AddVisitor> for Counter {
|
||||||
.into_actor(self);
|
.into_actor(self);
|
||||||
ctx.spawn(wait_for);
|
ctx.spawn(wait_for);
|
||||||
|
|
||||||
self.add_visitor();
|
self.0.add_visitor();
|
||||||
MessageResult(AddVisitorResult::new(&self))
|
MessageResult(AddVisitorResult::new(&self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +190,7 @@ impl Handler<GetCurrentVisitorCount> for Counter {
|
||||||
type Result = MessageResult<GetCurrentVisitorCount>;
|
type Result = MessageResult<GetCurrentVisitorCount>;
|
||||||
|
|
||||||
fn handle(&mut self, _: GetCurrentVisitorCount, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, _: GetCurrentVisitorCount, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
MessageResult(self.visitor_threshold)
|
MessageResult(self.0.get_visitors())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,14 @@ use derive_builder::Builder;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod embedded;
|
pub mod embedded;
|
||||||
|
#[allow(
|
||||||
use crate::defense::Defense;
|
unused_variables,
|
||||||
use crate::errors::*;
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
dead_code,
|
||||||
|
unused_macros
|
||||||
|
)]
|
||||||
|
use crate::mcaptcha::*;
|
||||||
|
|
||||||
/// Describes actor handler trait impls that are required by a cache implementation
|
/// Describes actor handler trait impls that are required by a cache implementation
|
||||||
pub trait Master: actix::Actor + actix::Handler<AddVisitor> + actix::Handler<AddSite> {}
|
pub trait Master: actix::Actor + actix::Handler<AddVisitor> + actix::Handler<AddSite> {}
|
||||||
|
@ -53,60 +58,3 @@ pub struct AddSite {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub mcaptcha: MCaptcha,
|
pub mcaptcha: MCaptcha,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder for [MCaptcha]
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
|
||||||
pub struct MCaptchaBuilder {
|
|
||||||
visitor_threshold: u32,
|
|
||||||
defense: Option<Defense>,
|
|
||||||
duration: Option<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MCaptchaBuilder {
|
|
||||||
fn default() -> Self {
|
|
||||||
MCaptchaBuilder {
|
|
||||||
visitor_threshold: 0,
|
|
||||||
defense: None,
|
|
||||||
duration: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MCaptchaBuilder {
|
|
||||||
/// set defense
|
|
||||||
pub fn defense(&mut self, d: Defense) -> &mut Self {
|
|
||||||
self.defense = Some(d);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// set duration
|
|
||||||
pub fn duration(&mut self, d: u64) -> &mut Self {
|
|
||||||
self.duration = Some(d);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds new [MCaptcha]
|
|
||||||
pub fn build(self: &mut MCaptchaBuilder) -> CaptchaResult<MCaptcha> {
|
|
||||||
if self.duration.is_none() {
|
|
||||||
Err(CaptchaError::PleaseSetValue("duration".into()))
|
|
||||||
} else if self.defense.is_none() {
|
|
||||||
Err(CaptchaError::PleaseSetValue("defense".into()))
|
|
||||||
} else if self.duration <= Some(0) {
|
|
||||||
Err(CaptchaError::CaptchaDurationZero)
|
|
||||||
} else {
|
|
||||||
let m = MCaptcha {
|
|
||||||
duration: self.duration.unwrap(),
|
|
||||||
defense: self.defense.clone().unwrap(),
|
|
||||||
visitor_threshold: self.visitor_threshold,
|
|
||||||
};
|
|
||||||
Ok(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
|
||||||
pub struct MCaptcha {
|
|
||||||
visitor_threshold: u32,
|
|
||||||
defense: Defense,
|
|
||||||
duration: u64,
|
|
||||||
}
|
|
||||||
|
|
206
src/master/redis_master/mod.rs
Normal file
206
src/master/redis_master/mod.rs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* mCaptcha - A proof of work based DoS protection system
|
||||||
|
* Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use actix::dev::*;
|
||||||
|
use redis::cluster::ClusterClient;
|
||||||
|
//use redis::cluster::ClusterConnection;
|
||||||
|
use redis::Client;
|
||||||
|
//use redis::Connection;
|
||||||
|
use redis::RedisResult;
|
||||||
|
use redis::{aio::Connection, cluster::ClusterConnection};
|
||||||
|
|
||||||
|
//use crate::errors::*;
|
||||||
|
use crate::master::{AddSite, AddVisitor, Master as MasterTrait};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Redis {
|
||||||
|
Single(Client),
|
||||||
|
Cluster(ClusterClient),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RedisConnection {
|
||||||
|
Single(Connection),
|
||||||
|
Cluster(ClusterConnection),
|
||||||
|
}
|
||||||
|
|
||||||
|
const INCR: &str = "MCAPTCHA_CACHE.COUNT";
|
||||||
|
const GET: &str = "MCAPTCHA_CACHE.GET";
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Master {
|
||||||
|
pub redis: Redis,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! exec {
|
||||||
|
($cmd:expr, $con:expr) => {
|
||||||
|
match $con {
|
||||||
|
RedisConnection::Single(mut con) => $cmd.query_async(&mut con).await,
|
||||||
|
RedisConnection::Cluster(mut con) => $cmd.query(&mut con),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Master {
|
||||||
|
async fn add_visitor(&mut self, key: &str) {
|
||||||
|
let mut cmd = redis::cmd(INCR);
|
||||||
|
cmd.arg(&[key]);
|
||||||
|
let a: RedisResult<usize> = exec!(cmd, self.get_connection().await);
|
||||||
|
|
||||||
|
unimplemented!("Have to check return types of INCR command")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_visitors(&mut self, key: &str) {
|
||||||
|
let mut cmd = redis::cmd(GET);
|
||||||
|
cmd.arg(&[key]);
|
||||||
|
let a: RedisResult<usize> = exec!(cmd, self.get_connection().await);
|
||||||
|
|
||||||
|
unimplemented!("Have to check return types of GET command")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_connection(&mut self) -> RedisConnection {
|
||||||
|
match &self.redis {
|
||||||
|
Redis::Single(c) => {
|
||||||
|
let con = c.get_async_connection().await.unwrap();
|
||||||
|
RedisConnection::Single(con)
|
||||||
|
}
|
||||||
|
Redis::Cluster(c) => {
|
||||||
|
let con = c.get_connection().unwrap();
|
||||||
|
RedisConnection::Cluster(con)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn module_is_loaded(&mut self) -> () {
|
||||||
|
let mut cmd = redis::cmd("COMMAND");
|
||||||
|
cmd.arg(&["INFO", INCR]);
|
||||||
|
let a: RedisResult<usize> = exec!(cmd, self.get_connection().await);
|
||||||
|
|
||||||
|
let mut cmd = redis::cmd("COMMAND");
|
||||||
|
cmd.arg(&["INFO", GET]);
|
||||||
|
let a: RedisResult<usize> = exec!(cmd, self.get_connection().await);
|
||||||
|
|
||||||
|
unimplemented!("Have to check return types of INFO command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MasterTrait for Master {}
|
||||||
|
|
||||||
|
impl Actor for Master {
|
||||||
|
type Context = Context<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<AddVisitor> for Master {
|
||||||
|
type Result = MessageResult<AddVisitor>;
|
||||||
|
|
||||||
|
fn handle(&mut self, m: AddVisitor, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
let fut = async {
|
||||||
|
self.add_visitor(&m.0).await;
|
||||||
|
};
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<AddSite> for Master {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[derive(Clone)]
|
||||||
|
//pub struct Cluster(pub ClusterClient);
|
||||||
|
//#[derive(Clone)]
|
||||||
|
//pub struct Single(pub Client);
|
||||||
|
//
|
||||||
|
//pub trait Redis: 'static + Unpin + Clone {
|
||||||
|
// type Result;
|
||||||
|
// fn get_connection(&'static self) -> Self::Result;
|
||||||
|
//}
|
||||||
|
//impl Redis for Cluster {
|
||||||
|
// type Result = RedisResult<ClusterConnection>;
|
||||||
|
// fn get_connection(&self) -> Self::Result {
|
||||||
|
// self.0.get_connection()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl Redis for Single {
|
||||||
|
// type Result = impl Future;
|
||||||
|
// fn get_connection(&'static self) -> Self::Result {
|
||||||
|
// self.0.get_async_connection()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#[derive(Clone)]
|
||||||
|
//pub struct Master {
|
||||||
|
// pub redis: usize,
|
||||||
|
//}
|
||||||
|
|
||||||
|
//impl MasterTrait for Master {}
|
||||||
|
//
|
||||||
|
//impl Actor for Master {
|
||||||
|
// type Context = Context<Self>;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl Handler<AddVisitor> for Master {
|
||||||
|
// type Result = MessageResult<AddVisitor>;
|
||||||
|
//
|
||||||
|
// fn handle(&mut self, m: AddVisitor, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
// let fut = async {
|
||||||
|
// let test = "1";
|
||||||
|
// };
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl Handler<AddSite> for Master {
|
||||||
|
// type Result = ();
|
||||||
|
//
|
||||||
|
// fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//pub struct Master<T: Redis> {
|
||||||
|
// pub redis: T,
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl<T: Redis> MasterTrait for Master<T> {}
|
||||||
|
//
|
||||||
|
//impl<T: Redis> Actor for Master<T> {
|
||||||
|
// type Context = Context<Self>;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl<T: Redis> Handler<AddVisitor> for Master<T> {
|
||||||
|
// type Result = MessageResult<AddVisitor>;
|
||||||
|
//
|
||||||
|
// fn handle(&mut self, m: AddVisitor, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
// let fut = async {
|
||||||
|
// self.redis.get_connection();
|
||||||
|
// let test = "1";
|
||||||
|
// };
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl<T: Redis> Handler<AddSite> for Master<T> {
|
||||||
|
// type Result = ();
|
||||||
|
//
|
||||||
|
// fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
//}
|
118
src/mcaptcha.rs
Normal file
118
src/mcaptcha.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* mCaptcha - A proof of work based DoS protection system
|
||||||
|
* Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::defense::Defense;
|
||||||
|
use crate::errors::*;
|
||||||
|
|
||||||
|
/// Builder for [MCaptcha]
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct MCaptchaBuilder {
|
||||||
|
visitor_threshold: u32,
|
||||||
|
defense: Option<Defense>,
|
||||||
|
duration: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MCaptchaBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
MCaptchaBuilder {
|
||||||
|
visitor_threshold: 0,
|
||||||
|
defense: None,
|
||||||
|
duration: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MCaptchaBuilder {
|
||||||
|
/// set defense
|
||||||
|
pub fn defense(&mut self, d: Defense) -> &mut Self {
|
||||||
|
self.defense = Some(d);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set duration
|
||||||
|
pub fn duration(&mut self, d: u64) -> &mut Self {
|
||||||
|
self.duration = Some(d);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds new [MCaptcha]
|
||||||
|
pub fn build(self: &mut MCaptchaBuilder) -> CaptchaResult<MCaptcha> {
|
||||||
|
if self.duration.is_none() {
|
||||||
|
Err(CaptchaError::PleaseSetValue("duration".into()))
|
||||||
|
} else if self.defense.is_none() {
|
||||||
|
Err(CaptchaError::PleaseSetValue("defense".into()))
|
||||||
|
} else if self.duration <= Some(0) {
|
||||||
|
Err(CaptchaError::CaptchaDurationZero)
|
||||||
|
} else {
|
||||||
|
let m = MCaptcha {
|
||||||
|
duration: self.duration.unwrap(),
|
||||||
|
defense: self.defense.clone().unwrap(),
|
||||||
|
visitor_threshold: self.visitor_threshold,
|
||||||
|
};
|
||||||
|
Ok(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct MCaptcha {
|
||||||
|
visitor_threshold: u32,
|
||||||
|
defense: Defense,
|
||||||
|
duration: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MCaptcha {
|
||||||
|
/// increments the visitor count by one
|
||||||
|
#[inline]
|
||||||
|
pub fn add_visitor(&mut self) {
|
||||||
|
self.visitor_threshold += 1;
|
||||||
|
if self.visitor_threshold > self.defense.visitor_threshold() {
|
||||||
|
self.defense.tighten_up();
|
||||||
|
} else {
|
||||||
|
self.defense.loosen_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// decrements the visitor count by one
|
||||||
|
#[inline]
|
||||||
|
pub fn decrement_visitor(&mut self) {
|
||||||
|
if self.visitor_threshold > 0 {
|
||||||
|
self.visitor_threshold -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get current difficulty factor
|
||||||
|
#[inline]
|
||||||
|
pub fn get_difficulty(&self) -> u32 {
|
||||||
|
self.defense.get_difficulty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get [Counter]'s lifetime
|
||||||
|
#[inline]
|
||||||
|
pub fn get_duration(&self) -> u64 {
|
||||||
|
self.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get [Counter]'s current visitor_threshold
|
||||||
|
#[inline]
|
||||||
|
pub fn get_visitors(&self) -> u32 {
|
||||||
|
self.visitor_threshold
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue