diff --git a/Cargo.lock b/Cargo.lock index a8313f60..df8d458d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,26 +60,6 @@ dependencies = [ "trust-dns-resolver", ] -[[package]] -name = "actix-files" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d031468a7859f71674e5531bd05137e0ea5de05ec9a917314330b88c582e2e0a" -dependencies = [ - "actix-service", - "actix-web", - "bitflags", - "bytes 0.5.6", - "derive_more", - "futures-core", - "futures-util", - "log", - "mime", - "mime_guess", - "percent-encoding", - "v_htmlescape", -] - [[package]] name = "actix-http" version = "2.2.0" @@ -405,7 +385,7 @@ checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" dependencies = [ "getrandom 0.2.2", "once_cell", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -607,15 +587,6 @@ dependencies = [ "libc", ] -[[package]] -name = "buf-min" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881e704e61d0fb41d7c6c9ae2bd790eb8c13dc974ae102fb98c788b4fdea4349" -dependencies = [ - "bytes 0.6.0", -] - [[package]] name = "build_const" version = "0.2.1" @@ -640,12 +611,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" -[[package]] -name = "bytes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16" - [[package]] name = "bytes" version = "1.0.1" @@ -773,7 +738,7 @@ dependencies = [ "rand 0.8.3", "sha2", "time 0.2.26", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -1169,9 +1134,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" dependencies = [ "futures-channel", "futures-core", @@ -1184,9 +1149,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" dependencies = [ "futures-core", "futures-sink", @@ -1194,15 +1159,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" [[package]] name = "futures-executor" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" dependencies = [ "futures-core", "futures-task", @@ -1211,15 +1176,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" +checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" [[package]] name = "futures-macro" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1229,21 +1194,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" +checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" [[package]] name = "futures-task" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" +checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" [[package]] name = "futures-util" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" dependencies = [ "futures-channel", "futures-core", @@ -1275,7 +1240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -1315,7 +1280,6 @@ name = "guard" version = "0.1.0" dependencies = [ "actix", - "actix-files", "actix-http", "actix-identity", "actix-rt", @@ -1323,7 +1287,7 @@ dependencies = [ "argon2-creds", "cache-buster", "config", - "derive_builder 0.9.0", + "derive_builder 0.10.0", "derive_more", "futures", "lazy_static", @@ -1647,12 +1611,14 @@ dependencies = [ [[package]] name = "m_captcha" version = "0.1.3" -source = "git+https://github.com/mCaptcha/mCaptcha?branch=master#61ee89aee3e421ed7b3292bb3ad71c7e01a40b05" +source = "git+https://github.com/mCaptcha/mCaptcha?branch=master#2d120d6791d8a32e7b3e31a7c5f1b54e3b35f9ef" dependencies = [ "actix", "derive_builder 0.9.0", "derive_more", + "log", "pow_sha256", + "pretty_env_logger", "rand 0.8.3", "serde 1.0.125", "serde_json", @@ -1819,16 +1785,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check 0.1.5", -] - [[package]] name = "nom" version = "5.1.2" @@ -1837,7 +1793,7 @@ checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ "lexical-core", "memchr", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -1850,7 +1806,7 @@ dependencies = [ "funty", "lexical-core", "memchr", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2083,7 +2039,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2094,7 +2050,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2369,7 +2325,7 @@ dependencies = [ "itoap", "ryu", "sailfish-macros", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2714,7 +2670,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2912,7 +2868,7 @@ dependencies = [ "standback", "stdweb", "time-macros", - "version_check 0.9.3", + "version_check", "winapi 0.3.9", ] @@ -3112,7 +3068,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.3", + "version_check", ] [[package]] @@ -3185,38 +3141,6 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" -[[package]] -name = "v_escape" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccca9e73c678b882900cbaec16dae4d3662ace5a17774ac45af04e0f3988fafa" -dependencies = [ - "buf-min", - "v_escape_derive", -] - -[[package]] -name = "v_escape_derive" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c860ad1273f4eee7006cee05db20c9e60e5d24cba024a32e1094aa8e574f3668" -dependencies = [ - "nom 4.2.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "v_htmlescape" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db00c903248abee8499af60bf20d242e7882335bbbffd2614915184cbb207402" -dependencies = [ - "cfg-if 1.0.0", - "v_escape", -] - [[package]] name = "validator" version = "0.13.0" @@ -3256,12 +3180,6 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad9680608df133af2c1ddd5eaf1ddce91d60d61b6bc51494ef326458365a470a" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - [[package]] name = "version_check" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index 5d273995..9f7dbec2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,11 @@ actix = "0.10" actix-identity = "0.3" actix-http = "2.2" actix-rt = "1" -actix-files = "0.4" mime_guess = "2.0.3" rust-embed = "5.9.0" cache-buster = { version = "0.1", git = "https://github.com/realaravinth/cache-buster" } -futures = "0.3" +futures = "0.3.14" sqlx = { version = "0.4.0", features = [ "runtime-actix-rustls", "postgres" ] } argon2-creds = { version = "0.2", git = "https://github.com/realaravinth/argon2-creds", commit = "61f2d1d" } @@ -40,12 +39,12 @@ argon2-creds = { version = "0.2", git = "https://github.com/realaravinth/argon2- config = "0.11" validator = { version = "0.13", features = ["derive"]} -derive_builder = "0.9" +derive_builder = "0.10" derive_more = "0.99" serde = "1" serde_json = "1" -serde_yaml = "0.8" +serde_yaml = "0.8.17" url = "2.2" @@ -63,8 +62,8 @@ rand = "0.8" sailfish = "0.3.2" [build-dependencies] -serde_yaml = "0.8" +serde_yaml = "0.8.17" serde_json = "1" -yaml-rust = "0.4" +yaml-rust = "0.4.5" cache-buster = { version = "0.1", git = "https://github.com/realaravinth/cache-buster" } mime = "0.3.16" diff --git a/src/api/v1/mcaptcha/levels.rs b/src/api/v1/mcaptcha/levels.rs index 83f66c8f..0b0396eb 100644 --- a/src/api/v1/mcaptcha/levels.rs +++ b/src/api/v1/mcaptcha/levels.rs @@ -176,15 +176,15 @@ pub async fn get_levels( Ok(HttpResponse::Ok().json(levels)) } -#[derive(Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Levels { levels: I32Levels, } -#[derive(Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct I32Levels { - difficulty_factor: i32, - visitor_threshold: i32, + pub difficulty_factor: i32, + pub visitor_threshold: i32, } async fn get_levels_util(key: &str, username: &str, data: &Data) -> ServiceResult> { @@ -224,25 +224,16 @@ mod tests { const DEL_URL: &str = "/api/v1/mcaptcha/levels/delete"; const GET_URL: &str = "/api/v1/mcaptcha/levels/get"; - let l1 = Level { - difficulty_factor: 50, - visitor_threshold: 50, - }; - let l2 = Level { - difficulty_factor: 500, - visitor_threshold: 500, - }; - let levels = vec![l1, l2]; - { let data = Data::new().await; delete_user(NAME, &data).await; } register_and_signin(NAME, EMAIL, PASSWORD).await; - let (data, _, signin_resp, key) = add_token_util(NAME, PASSWORD).await; + let (data, _, signin_resp, key) = add_levels_util(NAME, PASSWORD).await; let cookies = get_cookie!(signin_resp); let mut app = get_app!(data).await; + /* let add_level = AddLevels { levels: levels.clone(), @@ -258,8 +249,12 @@ mod tests { ) .await; assert_eq!(add_token_resp.status(), StatusCode::OK); + */ // 2. get level + + let levels = vec![L1, L2]; + let get_level_resp = test::call_service( &mut app, post_request!(&key, GET_URL) diff --git a/src/api/v1/mcaptcha/pow.rs b/src/api/v1/mcaptcha/pow.rs index 22c074c5..497bde02 100644 --- a/src/api/v1/mcaptcha/pow.rs +++ b/src/api/v1/mcaptcha/pow.rs @@ -15,11 +15,15 @@ * along with this program. If not, see . */ +use actix::prelude::*; use actix_identity::Identity; use actix_web::{post, web, HttpResponse, Responder}; +use m_captcha::{defense::LevelBuilder, master::AddSiteBuilder, DefenseBuilder, MCaptchaBuilder}; use serde::{Deserialize, Serialize}; -use super::{get_random, is_authenticated}; +use super::duration::GetDurationResp; +use super::is_authenticated; +use super::levels::I32Levels; use crate::errors::*; use crate::Data; @@ -51,9 +55,134 @@ pub async fn get_config( .fetch_one(&data.db) .await?; - if let Some(x) = res.exists { - println!("{}", x); + if res.exists.is_none() { + return Err(ServiceError::TokenNotFound); + } + let payload = payload.into_inner(); + match res.exists { + Some(true) => { + (); + match data.captcha.get_pow(payload.key.clone()).await { + Some(config) => Ok(HttpResponse::Ok().json(config)), + None => { + init_mcaptcha(&data, &payload.key).await?; + let config = data + .captcha + .get_pow(payload.key) + .await + .expect("mcaptcha should be initialized and ready to go"); + Ok(HttpResponse::Ok().json(config)) + } + } + } + + Some(false) => Err(ServiceError::TokenNotFound), + None => Err(ServiceError::TokenNotFound), + } +} + +async fn init_mcaptcha(data: &Data, key: &str) -> ServiceResult<()> { + // get levels + let levels_fut = sqlx::query_as!( + I32Levels, + "SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE + config_id = ( + SELECT config_id FROM mcaptcha_config WHERE key = ($1) + );", + &key, + ) + .fetch_all(&data.db); + // get duration + let duration_fut = sqlx::query_as!( + GetDurationResp, + "SELECT duration FROM mcaptcha_config + WHERE key = $1", + &key, + ) + .fetch_one(&data.db); + //let (levels, duration) = futures::try_join!(levels_fut, duration_fut).await?; + let (levels, duration) = futures::try_join!(levels_fut, duration_fut)?; + + // build defense + let mut defense = DefenseBuilder::default(); + + for level in levels.iter() { + let level = LevelBuilder::default() + .visitor_threshold(level.visitor_threshold as u32) + .difficulty_factor(level.difficulty_factor as u32) + .unwrap() + .build() + .unwrap(); + defense.add_level(level).unwrap(); } - Ok(HttpResponse::Ok()) + let defense = defense.build()?; + + // create captcha + let mcaptcha = MCaptchaBuilder::default() + .defense(defense) + // leaky bucket algorithm's emission interval + .duration(duration.duration as u64) + // .cache(cache) + .build() + .unwrap() + .start(); + + // add captcha to master + let msg = AddSiteBuilder::default() + .id(key.into()) + .addr(mcaptcha.clone()) + .build() + .unwrap(); + data.captcha.master.send(msg).await.unwrap(); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + use m_captcha::pow::PoWConfig; + + use super::*; + use crate::api::v1::services as v1_services; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn get_pow_config_works() { + const NAME: &str = "powusrworks"; + const PASSWORD: &str = "testingpas"; + const EMAIL: &str = "randomuser@a.com"; + const GET_URL: &str = "/api/v1/mcaptcha/pow/config"; + // const UPDATE_URL: &str = "/api/v1/mcaptcha/domain/token/duration/update"; + + { + let data = Data::new().await; + delete_user(NAME, &data).await; + } + + register_and_signin(NAME, EMAIL, PASSWORD).await; + let (data, _, signin_resp, token_key) = add_levels_util(NAME, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let get_config_payload = GetConfigPayload { + key: token_key.key.clone(), + }; + + // update and check changes + + let get_config_resp = test::call_service( + &mut app, + post_request!(&get_config_payload, GET_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(get_config_resp.status(), StatusCode::OK); + let config: PoWConfig = test::read_body_json(get_config_resp).await; + assert_eq!(config.difficulty_factor, L1.difficulty_factor); + } } diff --git a/src/main.rs b/src/main.rs index 8fee1d73..86aed5ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,6 @@ */ use std::env; -use actix_files::Files; use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{ client::Client, error::InternalError, http::StatusCode, middleware, web::JsonConfig, App, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 4e1403d8..feb8c1e6 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -3,10 +3,12 @@ use actix_web::{ dev::ServiceResponse, http::{header, StatusCode}, }; +use m_captcha::defense::Level; use serde::Serialize; use super::*; use crate::api::v1::auth::{Login, Register}; +use crate::api::v1::mcaptcha::levels::AddLevels; use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails; use crate::api::v1::services as v1_services; use crate::data::Data; @@ -97,54 +99,9 @@ pub async fn signin<'a>(name: &'a str, password: &str) -> (data::Data, Login, Se ) .await; assert_eq!(signin_resp.status(), StatusCode::OK); - (data, creds, signin_resp) } -///// register and signin and domain -///// bypasses domain verification, use with care -//pub async fn add_domain_util( -// name: &str, -// password: &str, -// domain: &str, -//) -> (data::Data, Login, ServiceResponse) { -// use crate::api::v1::mcaptcha::domains::Domain; -// use url::Url; -// -// let (data, creds, signin_resp) = signin(name, password).await; -// let cookies = get_cookie!(signin_resp); -// let mut app = get_app!(data).await; -// -// // 1. add domain -// let add_domain = Domain { -// name: domain.into(), -// }; -// -// let add_domain_resp = test::call_service( -// &mut app, -// post_request!(&add_domain, "/api/v1/mcaptcha/domain/add") -// .cookie(cookies.clone()) -// .to_request(), -// ) -// .await; -// assert_eq!(add_domain_resp.status(), StatusCode::OK); -// -// // verification work around -// let url = Url::parse(domain).unwrap(); -// let host = url.host_str().unwrap(); -// sqlx::query!( -// "INSERT INTO mcaptcha_domains_verified (name, owner_id) VALUES -// ($1, (SELECT ID from mcaptcha_users WHERE name = $2))", -// &host, -// &name -// ) -// .execute(&data.db) -// .await -// .unwrap(); -// -// (data, creds, signin_resp) -//} - pub async fn add_token_util( name: &str, password: &str, @@ -167,7 +124,7 @@ pub async fn add_token_util( ) .await; // let status = add_token_resp.status(); - // let txt: ErrorToResponse = test::read_body_json(add_token_resp).await; + // let txt: errortoresponse = test::read_body_json(add_token_resp).await; // println!("{:?}", txt.error); // assert_eq!(add_token_resp.status(), StatusCode::OK); @@ -202,3 +159,41 @@ pub async fn bad_post_req_test( let txt: ErrorToResponse = test::read_body_json(dup_token_resp).await; assert_eq!(txt.error, format!("{}", dup_err)); } + +pub const L1: Level = Level { + difficulty_factor: 50, + visitor_threshold: 50, +}; +pub const L2: Level = Level { + difficulty_factor: 500, + visitor_threshold: 500, +}; + +pub async fn add_levels_util( + name: &str, + password: &str, +) -> (data::Data, Login, ServiceResponse, MCaptchaDetails) { + const ADD_URL: &str = "/api/v1/mcaptcha/levels/add"; + let (data, creds, signin_resp, token_key) = add_token_util(name, password).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let levels = vec![L1, L2]; + + let add_level = AddLevels { + levels: levels.clone(), + key: token_key.key.clone(), + }; + + // 1. add level + let add_token_resp = test::call_service( + &mut app, + post_request!(&add_level, ADD_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(add_token_resp.status(), StatusCode::OK); + + (data, creds, signin_resp, token_key) +}