From ee548588a85a91ceeb3606a047e2611992e3e02e Mon Sep 17 00:00:00 2001 From: realaravinth Date: Wed, 24 Mar 2021 17:57:29 +0530 Subject: [PATCH] refactoring --- src/api/v1/mcaptcha/domains.rs | 153 ++++++++ src/api/v1/mcaptcha/duration.rs | 161 +++++++++ .../v1/{mcaptcha.rs => mcaptcha/levels.rs} | 339 ++++++++---------- src/api/v1/mcaptcha/mcaptcha.rs | 186 ++++++++++ src/api/v1/mcaptcha/mod.rs | 23 ++ src/api/v1/mod.rs | 26 +- src/api/v1/tests/mcaptcha.rs | 338 ----------------- src/api/v1/tests/mod.rs | 1 - src/tests/mod.rs | 6 +- 9 files changed, 682 insertions(+), 551 deletions(-) create mode 100644 src/api/v1/mcaptcha/domains.rs create mode 100644 src/api/v1/mcaptcha/duration.rs rename src/api/v1/{mcaptcha.rs => mcaptcha/levels.rs} (51%) create mode 100644 src/api/v1/mcaptcha/mcaptcha.rs create mode 100644 src/api/v1/mcaptcha/mod.rs delete mode 100644 src/api/v1/tests/mcaptcha.rs diff --git a/src/api/v1/mcaptcha/domains.rs b/src/api/v1/mcaptcha/domains.rs new file mode 100644 index 00000000..01fa4d5f --- /dev/null +++ b/src/api/v1/mcaptcha/domains.rs @@ -0,0 +1,153 @@ +/* +* Copyright (C) 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 . +*/ + +use actix_identity::Identity; +use actix_web::{post, web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; +use url::Url; + +use super::is_authenticated; +use crate::errors::*; +use crate::Data; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Domain { + pub name: String, +} + +#[post("/api/v1/mcaptcha/domain/add")] +pub async fn add_domain( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + let url = Url::parse(&payload.name)?; + if let Some(host) = url.host_str() { + let user = id.identity().unwrap(); + let res = sqlx::query!( + "INSERT INTO mcaptcha_domains (name, ID) VALUES + ($1, (SELECT ID FROM mcaptcha_users WHERE name = ($2) ));", + host, + user + ) + .execute(&data.db) + .await; + match res { + Err(e) => Err(dup_error(e, ServiceError::HostnameTaken)), + Ok(_) => Ok(HttpResponse::Ok()), + } + } else { + Err(ServiceError::NotAUrl) + } +} + +#[post("/api/v1/mcaptcha/domain/delete")] +pub async fn delete_domain( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + let url = Url::parse(&payload.name)?; + if let Some(host) = url.host_str() { + sqlx::query!("DELETE FROM mcaptcha_domains WHERE name = ($1)", host,) + .execute(&data.db) + .await?; + Ok(HttpResponse::Ok()) + } else { + Err(ServiceError::NotAUrl) + } +} + +// Workflow: +// 1. Sign up +// 2. Sign in +// 3. Add domain(DNS TXT record verification? / put string at path) +// 4. Create token +// 5. Add levels +// 6. Update duration +// 7. Start syatem + +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + + use super::*; + use crate::api::v1::services as v1_services; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn add_domains_work() { + const NAME: &str = "testuserdomainn"; + const PASSWORD: &str = "longpassworddomain"; + const EMAIL: &str = "testuserdomain@a.com"; + const DOMAIN: &str = "http://example.com"; + const ADD_URL: &str = "/api/v1/mcaptcha/domain/add"; + + { + let data = Data::new().await; + delete_user(NAME, &data).await; + } + + register_and_signin(NAME, EMAIL, PASSWORD).await; + + // 1. add domain + let (data, _, signin_resp) = add_domain_util(NAME, PASSWORD, DOMAIN).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let mut domain = Domain { + name: DOMAIN.into(), + }; + + // 2. duplicate domain + bad_post_req_test( + NAME, + PASSWORD, + ADD_URL, + &domain, + ServiceError::HostnameTaken, + StatusCode::BAD_REQUEST, + ) + .await; + + // 3. delete domain + let del_domain_resp = test::call_service( + &mut app, + post_request!(&domain, "/api/v1/mcaptcha/domain/delete") + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(del_domain_resp.status(), StatusCode::OK); + + // 4. not a URL test for adding domain + domain.name = "testing".into(); + bad_post_req_test( + NAME, + PASSWORD, + ADD_URL, + &domain, + ServiceError::NotAUrl, + StatusCode::BAD_REQUEST, + ) + .await; + } +} diff --git a/src/api/v1/mcaptcha/duration.rs b/src/api/v1/mcaptcha/duration.rs new file mode 100644 index 00000000..f2c1086f --- /dev/null +++ b/src/api/v1/mcaptcha/duration.rs @@ -0,0 +1,161 @@ +/* +* Copyright (C) 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 . +*/ + +use actix_identity::Identity; +use actix_web::{post, web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; + +use super::is_authenticated; +use crate::errors::*; +use crate::Data; + +#[derive(Deserialize, Serialize)] +pub struct UpdateDuration { + pub token_name: String, + pub duration: i32, +} + +#[post("/api/v1/mcaptcha/domain/token/duration/update")] +pub async fn update_duration( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + + if payload.duration > 0 { + sqlx::query!( + "UPDATE mcaptcha_config set duration = $1 WHERE + name = $2;", + &payload.duration, + &payload.token_name, + ) + .execute(&data.db) + .await?; + + Ok(HttpResponse::Ok()) + } else { + // when mCaptcha/mCaptcha #2 is fixed, this wont be necessary + Err(ServiceError::CaptchaError( + m_captcha::errors::CaptchaError::DifficultyFactorZero, + )) + } +} + +#[derive(Deserialize, Serialize)] +pub struct GetDurationResp { + pub duration: i32, +} + +#[derive(Deserialize, Serialize)] +pub struct GetDuration { + pub token: String, +} + +#[post("/api/v1/mcaptcha/domain/token/duration/get")] +pub async fn get_duration( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + + let duration = sqlx::query_as!( + GetDurationResp, + "SELECT duration FROM mcaptcha_config WHERE + name = $1;", + &payload.token, + ) + .fetch_one(&data.db) + .await?; + Ok(HttpResponse::Ok().json(duration)) +} + +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + + use super::*; + use crate::api::v1::services as v1_services; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn update_duration() { + const NAME: &str = "testuserduration"; + const PASSWORD: &str = "longpassworddomain"; + const EMAIL: &str = "testuserduration@a.com"; + const DOMAIN: &str = "http://duration.example.com"; + const TOKEN_NAME: &str = "duration_routes_token"; + const GET_URL: &str = "/api/v1/mcaptcha/domain/token/duration/get"; + 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) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let update = UpdateDuration { + token_name: TOKEN_NAME.into(), + duration: 40, + }; + + let get = GetDuration { + token: TOKEN_NAME.into(), + }; + + // check default + + let get_level_resp = test::call_service( + &mut app, + post_request!(&get, GET_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(get_level_resp.status(), StatusCode::OK); + let res_levels: GetDurationResp = test::read_body_json(get_level_resp).await; + assert_eq!(res_levels.duration, 30); + + // update and check changes + + let update_duration = test::call_service( + &mut app, + post_request!(&update, UPDATE_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(update_duration.status(), StatusCode::OK); + let get_level_resp = test::call_service( + &mut app, + post_request!(&get, GET_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(get_level_resp.status(), StatusCode::OK); + let res_levels: GetDurationResp = test::read_body_json(get_level_resp).await; + assert_eq!(res_levels.duration, 40); + } +} diff --git a/src/api/v1/mcaptcha.rs b/src/api/v1/mcaptcha/levels.rs similarity index 51% rename from src/api/v1/mcaptcha.rs rename to src/api/v1/mcaptcha/levels.rs index 1b1564e7..67a9371c 100644 --- a/src/api/v1/mcaptcha.rs +++ b/src/api/v1/mcaptcha/levels.rs @@ -19,143 +19,11 @@ use actix_identity::Identity; use actix_web::{post, web, HttpResponse, Responder}; use m_captcha::{defense::Level, DefenseBuilder}; use serde::{Deserialize, Serialize}; -use url::Url; -use super::auth::is_authenticated; +use super::is_authenticated; use crate::errors::*; use crate::Data; -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Domain { - pub name: String, -} - -#[post("/api/v1/mcaptcha/domain/add")] -pub async fn add_domain( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - let url = Url::parse(&payload.name)?; - if let Some(host) = url.host_str() { - let user = id.identity().unwrap(); - let res = sqlx::query!( - "INSERT INTO mcaptcha_domains (name, ID) VALUES - ($1, (SELECT ID FROM mcaptcha_users WHERE name = ($2) ));", - host, - user - ) - .execute(&data.db) - .await; - match res { - Err(e) => Err(dup_error(e, ServiceError::HostnameTaken)), - Ok(_) => Ok(HttpResponse::Ok()), - } - } else { - Err(ServiceError::NotAUrl) - } -} - -#[post("/api/v1/mcaptcha/domain/delete")] -pub async fn delete_domain( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - let url = Url::parse(&payload.name)?; - if let Some(host) = url.host_str() { - sqlx::query!("DELETE FROM mcaptcha_domains WHERE name = ($1)", host,) - .execute(&data.db) - .await?; - Ok(HttpResponse::Ok()) - } else { - Err(ServiceError::NotAUrl) - } -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct CreateToken { - pub name: String, - pub domain: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct TokenKeyPair { - pub name: String, - pub key: String, -} - -#[post("/api/v1/mcaptcha/domain/token/add")] -pub async fn add_mcaptcha( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - let key = get_random(32); - let url = Url::parse(&payload.domain)?; - println!("got req"); - if let Some(host) = url.host_str() { - let res = sqlx::query!( - "INSERT INTO mcaptcha_config - (name, key, domain_name) - VALUES ($1, $2, ( - SELECT name FROM mcaptcha_domains WHERE name = ($3)))", - &payload.name, - &key, - &host, - ) - .execute(&data.db) - .await; - - match res { - Err(e) => Err(dup_error(e, ServiceError::TokenNameTaken)), - Ok(_) => { - let resp = TokenKeyPair { - key, - name: payload.into_inner().name, - }; - - Ok(HttpResponse::Ok().json(resp)) - } - } - } else { - Err(ServiceError::NotAUrl) - } -} - -#[post("/api/v1/mcaptcha/domain/token/delete")] -pub async fn delete_mcaptcha( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - sqlx::query!( - "DELETE FROM mcaptcha_config WHERE name = ($1)", - &payload.name, - ) - .execute(&data.db) - .await?; - Ok(HttpResponse::Ok()) -} - -fn get_random(len: usize) -> String { - use std::iter; - - use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; - - let mut rng: ThreadRng = thread_rng(); - - iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .map(char::from) - .take(len) - .collect::() -} - #[derive(Serialize, Deserialize)] pub struct AddLevels { pub levels: Vec, @@ -287,63 +155,6 @@ pub async fn get_levels( Ok(HttpResponse::Ok().json(levels)) } -#[derive(Deserialize, Serialize)] -pub struct Duration { - pub token_name: String, - pub duration: i32, -} - -#[post("/api/v1/mcaptcha/domain/token/duration/update")] -pub async fn update_duration( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - - if payload.duration > 0 { - sqlx::query!( - "UPDATE mcaptcha_config set duration = $1 WHERE - name = $2;", - &payload.duration, - &payload.token_name, - ) - .execute(&data.db) - .await?; - - Ok(HttpResponse::Ok()) - } else { - // when mCaptcha/mCaptcha #2 is fixed, this wont be necessary - Err(ServiceError::CaptchaError( - m_captcha::errors::CaptchaError::DifficultyFactorZero, - )) - } -} - -#[derive(Deserialize, Serialize)] -pub struct GetDuration { - pub duration: i32, -} - -#[post("/api/v1/mcaptcha/domain/token/duration/get")] -pub async fn get_duration( - payload: web::Json, - data: web::Data, - id: Identity, -) -> ServiceResult { - is_authenticated(&id)?; - - let duration = sqlx::query_as!( - GetDuration, - "SELECT duration FROM mcaptcha_config WHERE - name = $1;", - &payload.token, - ) - .fetch_one(&data.db) - .await?; - Ok(HttpResponse::Ok().json(duration)) -} - #[derive(Deserialize, Serialize)] pub struct Levels { levels: I32Levels, @@ -370,11 +181,143 @@ async fn get_levels_util(name: &str, data: &Data) -> ServiceResult = test::read_body_json(get_level_resp).await; + assert_eq!(res_levels, levels); + + // 3. update level + + let l1 = Level { + difficulty_factor: 10, + visitor_threshold: 10, + }; + let l2 = Level { + difficulty_factor: 5000, + visitor_threshold: 5000, + }; + let levels = vec![l1, l2]; + let add_level = AddLevels { + levels: levels.clone(), + name: TOKEN_NAME.into(), + }; + let add_token_resp = test::call_service( + &mut app, + post_request!(&add_level, UPDATE_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(add_token_resp.status(), StatusCode::OK); + let get_level_resp = test::call_service( + &mut app, + post_request!(&get_level, GET_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(get_level_resp.status(), StatusCode::OK); + let res_levels: Vec = test::read_body_json(get_level_resp).await; + assert_eq!(res_levels, levels); + + // 4. delete level + let l1 = Level { + difficulty_factor: 10, + visitor_threshold: 10, + }; + let l2 = Level { + difficulty_factor: 5000, + visitor_threshold: 5000, + }; + let levels = vec![l1, l2]; + let add_level = AddLevels { + levels: levels.clone(), + name: TOKEN_NAME.into(), + }; + let add_token_resp = test::call_service( + &mut app, + post_request!(&add_level, DEL_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(add_token_resp.status(), StatusCode::OK); + let get_level_resp = test::call_service( + &mut app, + post_request!(&get_level, GET_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(get_level_resp.status(), StatusCode::OK); + let res_levels: Vec = test::read_body_json(get_level_resp).await; + assert_eq!(res_levels, Vec::new()); + } +} diff --git a/src/api/v1/mcaptcha/mcaptcha.rs b/src/api/v1/mcaptcha/mcaptcha.rs new file mode 100644 index 00000000..d844e91e --- /dev/null +++ b/src/api/v1/mcaptcha/mcaptcha.rs @@ -0,0 +1,186 @@ +/* +* Copyright (C) 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 . +*/ + +use actix_identity::Identity; +use actix_web::{post, web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; +use url::Url; + +use super::is_authenticated; +use crate::errors::*; +use crate::Data; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct MCaptchaID { + pub name: String, + pub domain: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct MCaptchaDetails { + pub name: String, + pub key: String, +} + +#[post("/api/v1/mcaptcha/domain/token/add")] +pub async fn add_mcaptcha( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + let key = get_random(32); + let url = Url::parse(&payload.domain)?; + println!("got req"); + if let Some(host) = url.host_str() { + let res = sqlx::query!( + "INSERT INTO mcaptcha_config + (name, key, domain_name) + VALUES ($1, $2, ( + SELECT name FROM mcaptcha_domains WHERE name = ($3)))", + &payload.name, + &key, + &host, + ) + .execute(&data.db) + .await; + + match res { + Err(e) => Err(dup_error(e, ServiceError::TokenNameTaken)), + Ok(_) => { + let resp = MCaptchaDetails { + key, + name: payload.into_inner().name, + }; + + Ok(HttpResponse::Ok().json(resp)) + } + } + } else { + Err(ServiceError::NotAUrl) + } +} + +#[post("/api/v1/mcaptcha/domain/token/delete")] +pub async fn delete_mcaptcha( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + is_authenticated(&id)?; + sqlx::query!( + "DELETE FROM mcaptcha_config WHERE name = ($1)", + &payload.name, + ) + .execute(&data.db) + .await?; + Ok(HttpResponse::Ok()) +} + +fn get_random(len: usize) -> String { + use std::iter; + + use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; + + let mut rng: ThreadRng = thread_rng(); + + iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(len) + .collect::() +} + +// Workflow: +// 1. Sign up +// 2. Sign in +// 3. Add domain(DNS TXT record verification? / put string at path) +// 4. Create token +// 5. Add levels +// 6. Update duration +// 7. Start syatem + +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + + use super::*; + use crate::api::v1::services as v1_services; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn add_mcaptcha_works() { + const NAME: &str = "testusermcaptcha"; + const PASSWORD: &str = "longpassworddomain"; + const EMAIL: &str = "testusermcaptcha@a.com"; + const DOMAIN: &str = "http://mcaptcha.example.com"; + const TOKEN_NAME: &str = "add_mcaptcha_works_token"; + const ADD_URL: &str = "/api/v1/mcaptcha/domain/token/add"; + const DEL_URL: &str = "/api/v1/mcaptcha/domain/token/delete"; + + { + let data = Data::new().await; + delete_user(NAME, &data).await; + } + + // 1. add mcaptcha token + register_and_signin(NAME, EMAIL, PASSWORD).await; + let (data, _, signin_resp) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let mut domain = MCaptchaID { + domain: DOMAIN.into(), + name: TOKEN_NAME.into(), + }; + + // 2. add duplicate mcaptha + bad_post_req_test( + NAME, + PASSWORD, + ADD_URL, + &domain, + ServiceError::TokenNameTaken, + StatusCode::BAD_REQUEST, + ) + .await; + + // 4. not a URL test for adding domain + domain.domain = "testing".into(); + bad_post_req_test( + NAME, + PASSWORD, + ADD_URL, + &domain, + ServiceError::NotAUrl, + StatusCode::BAD_REQUEST, + ) + .await; + + // 4. delete token + let del_token = test::call_service( + &mut app, + post_request!(&domain, DEL_URL) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(del_token.status(), StatusCode::OK); + } +} diff --git a/src/api/v1/mcaptcha/mod.rs b/src/api/v1/mcaptcha/mod.rs new file mode 100644 index 00000000..a4d34314 --- /dev/null +++ b/src/api/v1/mcaptcha/mod.rs @@ -0,0 +1,23 @@ +/* +* Copyright (C) 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 . +*/ + +pub mod domains; +pub mod duration; +pub mod levels; +pub mod mcaptcha; + +pub use super::auth::is_authenticated; diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs index e79480cb..9e619636 100644 --- a/src/api/v1/mod.rs +++ b/src/api/v1/mod.rs @@ -29,19 +29,23 @@ pub fn services(cfg: &mut ServiceConfig) { cfg.service(auth::delete_account); // mcaptcha - // 1. domain and mcaptcha - cfg.service(mcaptcha::add_domain); - cfg.service(mcaptcha::delete_domain); - cfg.service(mcaptcha::add_mcaptcha); - cfg.service(mcaptcha::delete_mcaptcha); + // domain + cfg.service(mcaptcha::domains::add_domain); + cfg.service(mcaptcha::domains::delete_domain); + + // mcaptcha + cfg.service(mcaptcha::mcaptcha::add_mcaptcha); + cfg.service(mcaptcha::mcaptcha::delete_mcaptcha); + // levels - cfg.service(mcaptcha::add_levels); - cfg.service(mcaptcha::update_levels); - cfg.service(mcaptcha::delete_levels); - cfg.service(mcaptcha::get_levels); + cfg.service(mcaptcha::levels::add_levels); + cfg.service(mcaptcha::levels::update_levels); + cfg.service(mcaptcha::levels::delete_levels); + cfg.service(mcaptcha::levels::get_levels); + // duration - cfg.service(mcaptcha::update_duration); - cfg.service(mcaptcha::get_duration); + cfg.service(mcaptcha::duration::update_duration); + cfg.service(mcaptcha::duration::get_duration); // meta cfg.service(meta::build_details); diff --git a/src/api/v1/tests/mcaptcha.rs b/src/api/v1/tests/mcaptcha.rs deleted file mode 100644 index 1e5f4d86..00000000 --- a/src/api/v1/tests/mcaptcha.rs +++ /dev/null @@ -1,338 +0,0 @@ -/* -* Copyright (C) 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 . -*/ - -use actix_web::http::{header, StatusCode}; -use actix_web::test; -use m_captcha::defense::Level; - -use crate::api::v1::mcaptcha::*; -use crate::api::v1::services as v1_services; -use crate::errors::*; -use crate::tests::*; -use crate::*; - -#[actix_rt::test] -async fn add_domains_work() { - const NAME: &str = "testuserdomainn"; - const PASSWORD: &str = "longpassworddomain"; - const EMAIL: &str = "testuserdomain@a.com"; - const DOMAIN: &str = "http://example.com"; - const ADD_URL: &str = "/api/v1/mcaptcha/domain/add"; - - { - let data = Data::new().await; - delete_user(NAME, &data).await; - } - - register_and_signin(NAME, EMAIL, PASSWORD).await; - - // 1. add domain - let (data, _, signin_resp) = add_domain_util(NAME, PASSWORD, DOMAIN).await; - let cookies = get_cookie!(signin_resp); - let mut app = get_app!(data).await; - - let mut domain = Domain { - name: DOMAIN.into(), - }; - - // 2. duplicate domain - bad_post_req_test( - NAME, - PASSWORD, - ADD_URL, - &domain, - ServiceError::HostnameTaken, - StatusCode::BAD_REQUEST, - ) - .await; - - // 3. delete domain - let del_domain_resp = test::call_service( - &mut app, - post_request!(&domain, "/api/v1/mcaptcha/domain/delete") - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(del_domain_resp.status(), StatusCode::OK); - - // 4. not a URL test for adding domain - domain.name = "testing".into(); - bad_post_req_test( - NAME, - PASSWORD, - ADD_URL, - &domain, - ServiceError::NotAUrl, - StatusCode::BAD_REQUEST, - ) - .await; -} - -#[actix_rt::test] -async fn add_mcaptcha_works() { - const NAME: &str = "testusermcaptcha"; - const PASSWORD: &str = "longpassworddomain"; - const EMAIL: &str = "testusermcaptcha@a.com"; - const DOMAIN: &str = "http://mcaptcha.example.com"; - const TOKEN_NAME: &str = "add_mcaptcha_works_token"; - const ADD_URL: &str = "/api/v1/mcaptcha/domain/token/add"; - const DEL_URL: &str = "/api/v1/mcaptcha/domain/token/delete"; - - { - let data = Data::new().await; - delete_user(NAME, &data).await; - } - - // 1. add mcaptcha token - register_and_signin(NAME, EMAIL, PASSWORD).await; - let (data, _, signin_resp) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await; - let cookies = get_cookie!(signin_resp); - let mut app = get_app!(data).await; - - let mut domain = CreateToken { - domain: DOMAIN.into(), - name: TOKEN_NAME.into(), - }; - - // 2. add duplicate mcaptha - bad_post_req_test( - NAME, - PASSWORD, - ADD_URL, - &domain, - ServiceError::TokenNameTaken, - StatusCode::BAD_REQUEST, - ) - .await; - - // 4. not a URL test for adding domain - domain.domain = "testing".into(); - bad_post_req_test( - NAME, - PASSWORD, - ADD_URL, - &domain, - ServiceError::NotAUrl, - StatusCode::BAD_REQUEST, - ) - .await; - - // 4. delete token - let del_token = test::call_service( - &mut app, - post_request!(&domain, DEL_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(del_token.status(), StatusCode::OK); -} - -#[actix_rt::test] -async fn level_routes_work() { - const NAME: &str = "testuserlevelroutes"; - const PASSWORD: &str = "longpassworddomain"; - const EMAIL: &str = "testuserlevelrouts@a.com"; - const DOMAIN: &str = "http://level.example.com"; - const TOKEN_NAME: &str = "level_routes_work"; - const ADD_URL: &str = "/api/v1/mcaptcha/domain/token/levels/add"; - const UPDATE_URL: &str = "/api/v1/mcaptcha/domain/token/levels/update"; - const DEL_URL: &str = "/api/v1/mcaptcha/domain/token/levels/delete"; - const GET_URL: &str = "/api/v1/mcaptcha/domain/token/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 add_level = AddLevels { - levels: levels.clone(), - name: TOKEN_NAME.into(), - }; - - let get_level = GetLevels { - token: TOKEN_NAME.into(), - }; - - { - let data = Data::new().await; - delete_user(NAME, &data).await; - } - - register_and_signin(NAME, EMAIL, PASSWORD).await; - let (data, _, signin_resp) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await; - let cookies = get_cookie!(signin_resp); - let mut app = get_app!(data).await; - - // 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); - - // 2. get level - let get_level_resp = test::call_service( - &mut app, - post_request!(&get_level, GET_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(get_level_resp.status(), StatusCode::OK); - let res_levels: Vec = test::read_body_json(get_level_resp).await; - assert_eq!(res_levels, levels); - - // 3. update level - - let l1 = Level { - difficulty_factor: 10, - visitor_threshold: 10, - }; - let l2 = Level { - difficulty_factor: 5000, - visitor_threshold: 5000, - }; - let levels = vec![l1, l2]; - let add_level = AddLevels { - levels: levels.clone(), - name: TOKEN_NAME.into(), - }; - let add_token_resp = test::call_service( - &mut app, - post_request!(&add_level, UPDATE_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(add_token_resp.status(), StatusCode::OK); - let get_level_resp = test::call_service( - &mut app, - post_request!(&get_level, GET_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(get_level_resp.status(), StatusCode::OK); - let res_levels: Vec = test::read_body_json(get_level_resp).await; - assert_eq!(res_levels, levels); - - // 4. delete level - let l1 = Level { - difficulty_factor: 10, - visitor_threshold: 10, - }; - let l2 = Level { - difficulty_factor: 5000, - visitor_threshold: 5000, - }; - let levels = vec![l1, l2]; - let add_level = AddLevels { - levels: levels.clone(), - name: TOKEN_NAME.into(), - }; - let add_token_resp = test::call_service( - &mut app, - post_request!(&add_level, DEL_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(add_token_resp.status(), StatusCode::OK); - let get_level_resp = test::call_service( - &mut app, - post_request!(&get_level, GET_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(get_level_resp.status(), StatusCode::OK); - let res_levels: Vec = test::read_body_json(get_level_resp).await; - assert_eq!(res_levels, Vec::new()); -} - -#[actix_rt::test] -async fn update_duration() { - const NAME: &str = "testuserduration"; - const PASSWORD: &str = "longpassworddomain"; - const EMAIL: &str = "testuserduration@a.com"; - const DOMAIN: &str = "http://duration.example.com"; - const TOKEN_NAME: &str = "duration_routes_token"; - const GET_URL: &str = "/api/v1/mcaptcha/domain/token/duration/get"; - 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) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await; - let cookies = get_cookie!(signin_resp); - let mut app = get_app!(data).await; - - let update = Duration { - token_name: TOKEN_NAME.into(), - duration: 40, - }; - - let get = GetLevels { - token: TOKEN_NAME.into(), - }; - - // check default - - let get_level_resp = test::call_service( - &mut app, - post_request!(&get, GET_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(get_level_resp.status(), StatusCode::OK); - let res_levels: GetDuration = test::read_body_json(get_level_resp).await; - assert_eq!(res_levels.duration, 30); - - // update and check changes - - let update_duration = test::call_service( - &mut app, - post_request!(&update, UPDATE_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(update_duration.status(), StatusCode::OK); - let get_level_resp = test::call_service( - &mut app, - post_request!(&get, GET_URL) - .cookie(cookies.clone()) - .to_request(), - ) - .await; - assert_eq!(get_level_resp.status(), StatusCode::OK); - let res_levels: GetDuration = test::read_body_json(get_level_resp).await; - assert_eq!(res_levels.duration, 40); -} diff --git a/src/api/v1/tests/mod.rs b/src/api/v1/tests/mod.rs index 2ab2ce23..edcf8801 100644 --- a/src/api/v1/tests/mod.rs +++ b/src/api/v1/tests/mod.rs @@ -16,4 +16,3 @@ */ mod auth; -mod mcaptcha; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index e1a79681..35f91345 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -102,7 +102,7 @@ pub async fn add_domain_util( password: &str, domain: &str, ) -> (data::Data, Login, ServiceResponse) { - use crate::api::v1::mcaptcha::Domain; + use crate::api::v1::mcaptcha::domains::Domain; let (data, creds, signin_resp) = signin(name, password).await; let cookies = get_cookie!(signin_resp); @@ -131,7 +131,7 @@ pub async fn add_token_util( domain: &str, token_name: &str, ) -> (data::Data, Login, ServiceResponse) { - use crate::api::v1::mcaptcha::CreateToken; + use crate::api::v1::mcaptcha::mcaptcha::MCaptchaID; const ADD_URL: &str = "/api/v1/mcaptcha/domain/token/add"; @@ -140,7 +140,7 @@ pub async fn add_token_util( let mut app = get_app!(data).await; // 1. add mcaptcha token - let domain = CreateToken { + let domain = MCaptchaID { domain: domain.into(), name: token_name.into(), };