      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200

    /*
     * 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/>.
     */
    //! mCaptcha is a proof of work based Denaial-of-Service attack protection system.
    //! This is is a server library that you can embed in your services to protect your
    //! servers.
    //!
    //! A commercial managed solution is in the works but I'd much rather prefer
    //! folks host their own instances as it will make the more decentralized and free.
    //!
    //! In mCaptcha, defense is adjusted in discrete levels that depend on the
    //! ammount of traffic that a service is experiencing. So users of this library are
    //! requested to benchmark their target machines before configuring their mCaptcha
    //! component.
    //!
    //! ## Terminology:
    //! - Difficulty(Factor): Minimum ammount of work that a client must do to make a valid
    //! request.
    //! - [Defense]: A datatype that various visitor-difficulty mappigns
    //! - Visitor: Smallest unit of traffic, usually a single request. The more you have, the busier
    //! your service is. Determines mCaptcha defense defense
    //! - Visitor threshold: The threshold at which [MCaptcha] will adjust defense defense
    //! - [Cache][crate::cache] : A datatype that implements [Save][crate::cache::Save]. Used to store
    //! PoW requirements to defend against replay attacks and dictionary attacks.
    //! - [Master][crate::master::Master]: A datatype that manages
    //! [MCaptcha][crate::mcaptcha::MCaptcha] actors. Works like a DNS for
    //! [AddVisitor][crate::mcaptcha::AddVisitor] messages.
    //! - [System][crate::system::System]: mCaptcha system that manages cache, master and provides
    //! useful abstractions. An mCaptcha system/instance can have only a single
    //! [System][crate::system::System]
    //!
    //! ## Example:
    //!
    //! ```rust
    //! use m_captcha::{
    //!     cache::{messages::VerifyCaptchaResult, HashCache},
    //!     master::{AddSiteBuilder, Master},
    //!     pow::{ConfigBuilder, Work},
    //!     system::SystemBuilder,
    //!     DefenseBuilder, LevelBuilder, MCaptchaBuilder,
    //! };
    //! // traits from actix needs to be in scope for starting actor
    //! use actix::prelude::*;
    //!
    //! #[actix_rt::main]
    //! async fn main() -> std::io::Result<()> {
    //!     // start cahce actor
    //!     // cache is used to store PoW requirements that are sent to clients
    //!     // This way, it can be verified that the client computed work over a config
    //!     // that _we_ sent. Offers protection against rainbow tables powered dictionary attacks
    //!     let cache = HashCache::default().start();
    //!
    //!     // create PoW config with unique salt. Salt has to be safely guarded.
    //!     // salts protect us from replay attacks
    //!     let pow = ConfigBuilder::default()
    //!         .salt("myrandomsaltisnotlongenoug".into())
    //!         .build()
    //!         .unwrap();
    //!
    //!     // start master actor. Master actor is responsible for managing MCaptcha actors
    //!     // each mCaptcha system should have only one master
    //!     let master = Master::new(5).start();
    //!
    //!     // Create system. System encapsulates master and cache and provides useful abstraction
    //!     // each mCaptcha system should have only one system
    //!     let system = SystemBuilder::default()
    //!         .master(master)
    //!         .cache(cache)
    //!         .pow(pow.clone())
    //!         .build()
    //!         .unwrap();
    //!
    //!     // configure defense. This is a per site configuration. A site can have several levels
    //!     // of defenses configured
    //!     let defense = DefenseBuilder::default()
    //!         // add as many defense as you see fit
    //!         .add_level(
    //!             LevelBuilder::default()
    //!                 // visitor_threshold is the threshold/limit at which
    //!                 // mCaptcha will adjust difficulty defense
    //!                 // it is advisable to set small values for the first
    //!                 // defense visitor_threshold and difficulty_factor
    //!                 // as this will be the work that clients will be
    //!                 // computing when there's no load
    //!                 .visitor_threshold(50)
    //!                 .difficulty_factor(500)
    //!                 .unwrap()
    //!                 .build()
    //!                 .unwrap(),
    //!         )
    //!         .unwrap()
    //!         .add_level(
    //!             LevelBuilder::default()
    //!                 .visitor_threshold(5000)
    //!                 .difficulty_factor(50000)
    //!                 .unwrap()
    //!                 .build()
    //!                 .unwrap(),
    //!         )
    //!         .unwrap()
    //!         .build()
    //!         .unwrap();
    //!
    //!     // create and start MCaptcha actor that uses the above defense configuration
    //!     // This is what manages the difficulty factor of sites that an mCaptcha protects
    //!     let mcaptcha = MCaptchaBuilder::default()
    //!         .defense(defense)
    //!         // leaky bucket algorithm's emission interval
    //!         .duration(30)
    //!         //   .cache(cache)
    //!         .build()
    //!         .unwrap()
    //!         .start();
    //!
    //!     // unique value identifying an MCaptcha actor
    //!     let mcaptcha_name = "batsense.net";
    //!
    //!     // add MCaptcha to Master
    //!     let msg = AddSiteBuilder::default()
    //!         .id(mcaptcha_name.into())
    //!         .addr(mcaptcha.clone())
    //!         .build()
    //!         .unwrap();
    //!     system.master.send(msg).await.unwrap();
    //!
    //!     // Get PoW config. Should be called everytime there's a visitor for a
    //!     // managed site(here mcaptcha_name)
    //!     let work_req = system.get_pow(mcaptcha_name.into()).await.unwrap();
    //!
    //!     // the following computation should be done on the client but for the purpose
    //!     // of this illustration, we are going to do it on the server it self
    //!     let work = pow
    //!         .prove_work(&work_req.string, work_req.difficulty_factor)
    //!         .unwrap();
    //!
    //!     // the payload that the client sends to the server
    //!     let payload = Work {
    //!         string: work_req.string,
    //!         result: work.result,
    //!         nonce: work.nonce,
    //!         key: mcaptcha_name.into(),
    //!     };
    //!
    //!     // Server evaluates client's work. Returns true if everything
    //!     // checksout and Err() if something fishy is happening
    //!     let res = system.verify_pow(payload.clone()).await;
    //!     assert!(res.is_ok());
    //!
    //!    // The client should submit the token to the mCaptcha protected service
    //!    // The service should validate the token received from the client
    //!    // with the mCaptcha server before processing client's
    //!    // request
    //!
    //!    // mcaptcha protected service sends the following paylaod to mCaptcha
    //!    // server:
    //!    let verify_msg = VerifyCaptchaResult {
    //!        token: res.unwrap(),
    //!        key: mcaptcha_name.into(),
    //!    };
    //!
    //!    // on mCaptcha server:
    //!    let res = system.validate_verification_tokens(verify_msg).await;
    //!    // mCaptcha will return true if token is valid and false if
    //!    // token is invalid
    //!    assert!(res.is_ok());
    //!    assert!(res.unwrap());
    //!
    //!    Ok(())
    //! }
    //! ```
    #![forbid(unsafe_code)]
    pub mod defense;
    pub mod errors;
    pub mod master;
    pub mod mcaptcha;

    /// message datatypes to interact with [MCaptcha] actor
    pub mod cache;
    pub mod pow;
    pub mod system;
    mod utils;

    pub use crate::cache::hashcache::HashCache;

    pub use defense::{Defense, DefenseBuilder, LevelBuilder};
    pub use mcaptcha::{MCaptcha, MCaptchaBuilder};