mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2025-02-17 08:59:46 +03:00
rm domains and added authorization check at all endpoints
This commit is contained in:
parent
646a92b28f
commit
4e7e8da574
12 changed files with 201 additions and 638 deletions
|
@ -1,4 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS mcaptcha_domains_verified (
|
||||
name VARCHAR(100) PRIMARY KEY NOT NULL UNIQUE,
|
||||
owner_id INTEGER references mcaptcha_users(ID) ON DELETE CASCADE NOT NULL
|
||||
);
|
|
@ -1,7 +1,7 @@
|
|||
CREATE TABLE IF NOT EXISTS mcaptcha_config (
|
||||
config_id SERIAL PRIMARY KEY NOT NULL,
|
||||
domain_name varchar(100) NOT NULL references mcaptcha_domains_verified(name) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL references mcaptcha_users(ID) ON DELETE CASCADE,
|
||||
key varchar(100) NOT NULL UNIQUE,
|
||||
name varchar(100) NOT NULL UNIQUE,
|
||||
name varchar(100) DEFAULT NULL,
|
||||
duration integer NOT NULL DEFAULT 30
|
||||
);
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS mcaptcha_domains_unverified (
|
||||
name VARCHAR(100) PRIMARY KEY NOT NULL,
|
||||
owner_id INTEGER references mcaptcha_users(ID) ON DELETE CASCADE NOT NULL,
|
||||
verified BOOLEAN DEFAULT NULL,
|
||||
verification_challenge VARCHAR(32) NOT NULL
|
||||
);
|
|
@ -1,324 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{client::Client, post, web, HttpResponse, Responder};
|
||||
//use awc::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use super::{get_random, 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<Domain>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.name)?;
|
||||
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
let user = id.identity().unwrap();
|
||||
let challenge = get_random(32);
|
||||
let res = sqlx::query!(
|
||||
"INSERT INTO mcaptcha_domains_unverified
|
||||
(name, owner_id, verification_challenge) VALUES
|
||||
($1, (SELECT ID FROM mcaptcha_users WHERE name = ($2) ), $3);",
|
||||
host,
|
||||
user,
|
||||
challenge
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await;
|
||||
match res {
|
||||
Err(e) => Err(dup_error(e, ServiceError::HostnameTaken)),
|
||||
Ok(_) => Ok(HttpResponse::Ok()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Challenge {
|
||||
verification_challenge: String,
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/verify/challenge/get")]
|
||||
pub async fn get_challenge(
|
||||
payload: web::Json<Domain>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.name)?;
|
||||
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
let user = id.identity().unwrap();
|
||||
let res = sqlx::query_as!(
|
||||
Challenge,
|
||||
"SELECT verification_challenge
|
||||
FROM mcaptcha_domains_unverified where
|
||||
name = $1 AND owner_id = (SELECT ID from mcaptcha_users where name = $2)",
|
||||
host,
|
||||
user,
|
||||
)
|
||||
.fetch_one(&data.db)
|
||||
.await?;
|
||||
Ok(HttpResponse::Ok().json(res))
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/verify/challenge/prove")]
|
||||
pub async fn verify(
|
||||
payload: web::Json<Domain>,
|
||||
data: web::Data<Data>,
|
||||
client: web::Data<Client>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
use crate::VERIFICATION_PATH;
|
||||
use futures::{future::TryFutureExt, try_join};
|
||||
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.name)?;
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
let user = id.identity().unwrap();
|
||||
let challenge_fut = sqlx::query_as!(
|
||||
Challenge,
|
||||
"SELECT verification_challenge
|
||||
FROM mcaptcha_domains_unverified where
|
||||
name = $1 AND owner_id = (SELECT ID from mcaptcha_users where name = $2)",
|
||||
&host,
|
||||
&user,
|
||||
)
|
||||
.fetch_one(&data.db)
|
||||
.map_err(|e| {
|
||||
let r: ServiceError = e.into();
|
||||
r
|
||||
});
|
||||
|
||||
let res_fut = client
|
||||
.get(format!("{}{}", url.to_string(), VERIFICATION_PATH))
|
||||
.send()
|
||||
.map_err(|e| {
|
||||
let r: ServiceError = e.into();
|
||||
r
|
||||
});
|
||||
|
||||
let (challenge, mut server_res) = try_join!(challenge_fut, res_fut)?;
|
||||
|
||||
let server_resp: Challenge = server_res
|
||||
.json()
|
||||
.await
|
||||
.map_err(|_| return ServiceError::ChallengeCourruption)?;
|
||||
|
||||
if server_resp.verification_challenge == challenge.verification_challenge {
|
||||
sqlx::query!(
|
||||
"INSERT INTO mcaptcha_domains_verified (name, owner_id) VALUES
|
||||
($1, (SELECT ID from mcaptcha_users WHERE name = $2))",
|
||||
&host,
|
||||
&user
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
||||
// TODO delete staging unverified
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
} else {
|
||||
Err(ServiceError::ChallengeVerificationFailure)
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/delete")]
|
||||
pub async fn delete_domain(
|
||||
payload: web::Json<Domain>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.name)?;
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
sqlx::query!(
|
||||
"DELETE FROM mcaptcha_domains_verified WHERE name = ($1)",
|
||||
host,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
// TODO check running actors and delete
|
||||
// if domain(api_key) matches mcaptcha actor id
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn domain_verification_works() {
|
||||
use crate::api::v1::tests::*;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
const NAME: &str = "testdomainveri";
|
||||
const PASSWORD: &str = "longpassworddomain";
|
||||
const EMAIL: &str = "domainverification@a.com";
|
||||
const DOMAIN: &str = "http://localhost:18001";
|
||||
const IP: &str = "localhost:18001";
|
||||
const CHALLENGE_GET: &str = "/api/v1/mcaptcha/domain/verify/challenge/get";
|
||||
const CHALLENGE_VERIFY: &str = "/api/v1/mcaptcha/domain/verify/challenge/prove";
|
||||
{
|
||||
let data = Data::new().await;
|
||||
delete_user(NAME, &data).await;
|
||||
}
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
thread::spawn(move || {
|
||||
actix_rt::System::new("").block_on(server(IP, tx));
|
||||
});
|
||||
let srv = rx.recv().unwrap();
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
let (data, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await;
|
||||
let cookies = get_cookie!(signin_resp);
|
||||
let mut app = test::init_service(
|
||||
App::new()
|
||||
.wrap(get_identity_service())
|
||||
.configure(v1_services)
|
||||
.data(data.clone())
|
||||
.data(client.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
let domain = Domain {
|
||||
name: DOMAIN.into(),
|
||||
};
|
||||
|
||||
let add_domain_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, "/api/v1/mcaptcha/domain/add")
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(add_domain_resp.status(), StatusCode::OK);
|
||||
|
||||
let get_challenge_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, CHALLENGE_GET)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(get_challenge_resp.status(), StatusCode::OK);
|
||||
let challenge: Challenge = test::read_body_json(get_challenge_resp).await;
|
||||
|
||||
client
|
||||
.post(format!("{}/{}/", DOMAIN, VERIFICATION_PATH))
|
||||
.send_json(&challenge)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let verify_challenge_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, CHALLENGE_VERIFY)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(verify_challenge_resp.status(), StatusCode::OK);
|
||||
srv.stop(true).await;
|
||||
}
|
||||
}
|
|
@ -20,12 +20,13 @@ use actix_web::{post, web, HttpResponse, Responder};
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::is_authenticated;
|
||||
use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails;
|
||||
use crate::errors::*;
|
||||
use crate::Data;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct UpdateDuration {
|
||||
pub token_name: String,
|
||||
pub key: String,
|
||||
pub duration: i32,
|
||||
}
|
||||
|
||||
|
@ -36,13 +37,15 @@ pub async fn update_duration(
|
|||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
if payload.duration > 0 {
|
||||
sqlx::query!(
|
||||
"UPDATE mcaptcha_config set duration = $1 WHERE
|
||||
name = $2;",
|
||||
"UPDATE mcaptcha_config set duration = $1
|
||||
WHERE key = $2 AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = $3)",
|
||||
&payload.duration,
|
||||
&payload.token_name,
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -68,17 +71,19 @@ pub struct GetDuration {
|
|||
|
||||
#[post("/api/v1/mcaptcha/domain/token/duration/get")]
|
||||
pub async fn get_duration(
|
||||
payload: web::Json<GetDuration>,
|
||||
payload: web::Json<MCaptchaDetails>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
let duration = sqlx::query_as!(
|
||||
GetDurationResp,
|
||||
"SELECT duration FROM mcaptcha_config WHERE
|
||||
name = $1;",
|
||||
&payload.token,
|
||||
"SELECT duration FROM mcaptcha_config
|
||||
WHERE key = $1 AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = $2)",
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.fetch_one(&data.db)
|
||||
.await?;
|
||||
|
@ -100,8 +105,6 @@ mod tests {
|
|||
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";
|
||||
|
||||
|
@ -111,24 +114,20 @@ mod tests {
|
|||
}
|
||||
|
||||
register_and_signin(NAME, EMAIL, PASSWORD).await;
|
||||
let (data, _, signin_resp) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await;
|
||||
let (data, _, signin_resp, token_key) = add_token_util(NAME, PASSWORD).await;
|
||||
let cookies = get_cookie!(signin_resp);
|
||||
let mut app = get_app!(data).await;
|
||||
|
||||
let update = UpdateDuration {
|
||||
token_name: TOKEN_NAME.into(),
|
||||
key: token_key.key.clone(),
|
||||
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)
|
||||
post_request!(&token_key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
@ -149,7 +148,7 @@ mod tests {
|
|||
assert_eq!(update_duration.status(), StatusCode::OK);
|
||||
let get_level_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get, GET_URL)
|
||||
post_request!(&token_key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
|
|
@ -21,6 +21,7 @@ use m_captcha::{defense::Level, DefenseBuilder};
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::is_authenticated;
|
||||
use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails;
|
||||
use crate::errors::*;
|
||||
use crate::Data;
|
||||
|
||||
|
@ -28,12 +29,12 @@ use crate::Data;
|
|||
pub struct AddLevels {
|
||||
pub levels: Vec<Level>,
|
||||
// name is config_name
|
||||
pub name: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
// TODO try for non-existent token names
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/levels/add")]
|
||||
#[post("/api/v1/mcaptcha/levels/add")]
|
||||
pub async fn add_levels(
|
||||
payload: web::Json<AddLevels>,
|
||||
data: web::Data<Data>,
|
||||
|
@ -41,6 +42,7 @@ pub async fn add_levels(
|
|||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let mut defense = DefenseBuilder::default();
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
for level in payload.levels.iter() {
|
||||
defense.add_level(level.clone())?;
|
||||
|
@ -55,10 +57,16 @@ pub async fn add_levels(
|
|||
"INSERT INTO mcaptcha_levels (
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
config_id) VALUES ($1, $2, (SELECT config_id FROM mcaptcha_config WHERE name = ($3) ));",
|
||||
config_id) VALUES (
|
||||
$1, $2, (
|
||||
SELECT config_id FROM mcaptcha_config WHERE
|
||||
key = ($3) AND user_id = (
|
||||
SELECT ID FROM mcaptcha_users WHERE name = $4
|
||||
)));",
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
&payload.name,
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -67,13 +75,14 @@ pub async fn add_levels(
|
|||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/levels/update")]
|
||||
#[post("/api/v1/mcaptcha/levels/update")]
|
||||
pub async fn update_levels(
|
||||
payload: web::Json<AddLevels>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
let mut defense = DefenseBuilder::default();
|
||||
|
||||
for level in payload.levels.iter() {
|
||||
|
@ -88,9 +97,13 @@ pub async fn update_levels(
|
|||
sqlx::query!(
|
||||
"DELETE FROM mcaptcha_levels
|
||||
WHERE config_id = (
|
||||
SELECT config_id FROM mcaptcha_config where name = ($1)
|
||||
SELECT config_id FROM mcaptcha_config where key = ($1)
|
||||
AND user_id = (
|
||||
SELECT ID from mcaptcha_users WHERE name = $2
|
||||
)
|
||||
)",
|
||||
&payload.name,
|
||||
&payload.key,
|
||||
&username
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -102,10 +115,17 @@ pub async fn update_levels(
|
|||
"INSERT INTO mcaptcha_levels (
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
config_id) VALUES ($1, $2, (SELECT config_id FROM mcaptcha_config WHERE name = ($3) ));",
|
||||
config_id) VALUES (
|
||||
$1, $2, (
|
||||
SELECT config_id FROM mcaptcha_config WHERE key = ($3) AND
|
||||
user_id = (
|
||||
SELECT ID from mcaptcha_users WHERE name = $4
|
||||
)
|
||||
));",
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
&payload.name,
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -114,23 +134,26 @@ pub async fn update_levels(
|
|||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/levels/delete")]
|
||||
#[post("/api/v1/mcaptcha/levels/delete")]
|
||||
pub async fn delete_levels(
|
||||
payload: web::Json<AddLevels>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
for level in payload.levels.iter() {
|
||||
let difficulty_factor = level.difficulty_factor as i32;
|
||||
sqlx::query!(
|
||||
"DELETE FROM mcaptcha_levels WHERE
|
||||
config_id = (
|
||||
SELECT config_id FROM mcaptcha_config WHERE name = ($1)
|
||||
SELECT config_id FROM mcaptcha_config WHERE key = $1 AND
|
||||
user_id = (SELECT ID from mcaptcha_users WHERE name = $3)
|
||||
) AND difficulty_factor = ($2);",
|
||||
&payload.name,
|
||||
&payload.key,
|
||||
difficulty_factor,
|
||||
&username
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -139,20 +162,16 @@ pub async fn delete_levels(
|
|||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct GetLevels {
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/levels/get")]
|
||||
#[post("/api/v1/mcaptcha/levels/get")]
|
||||
pub async fn get_levels(
|
||||
payload: web::Json<GetLevels>,
|
||||
payload: web::Json<MCaptchaDetails>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
let levels = get_levels_util(&payload.token, &data).await?;
|
||||
let levels = get_levels_util(&payload.key, &username, &data).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(levels))
|
||||
}
|
||||
|
@ -168,14 +187,16 @@ pub struct I32Levels {
|
|||
visitor_threshold: i32,
|
||||
}
|
||||
|
||||
async fn get_levels_util(name: &str, data: &Data) -> ServiceResult<Vec<I32Levels>> {
|
||||
async fn get_levels_util(key: &str, username: &str, data: &Data) -> ServiceResult<Vec<I32Levels>> {
|
||||
let levels = sqlx::query_as!(
|
||||
I32Levels,
|
||||
"SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE
|
||||
config_id = (
|
||||
SELECT config_id FROM mcaptcha_config WHERE name = ($1)
|
||||
SELECT config_id FROM mcaptcha_config WHERE key = ($1)
|
||||
AND user_id = (SELECT ID from mcaptcha_users WHERE name = $2)
|
||||
);",
|
||||
name
|
||||
key,
|
||||
&username
|
||||
)
|
||||
.fetch_all(&data.db)
|
||||
.await?;
|
||||
|
@ -198,12 +219,10 @@ mod tests {
|
|||
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";
|
||||
const ADD_URL: &str = "/api/v1/mcaptcha/levels/add";
|
||||
const UPDATE_URL: &str = "/api/v1/mcaptcha/levels/update";
|
||||
const DEL_URL: &str = "/api/v1/mcaptcha/levels/delete";
|
||||
const GET_URL: &str = "/api/v1/mcaptcha/levels/get";
|
||||
|
||||
let l1 = Level {
|
||||
difficulty_factor: 50,
|
||||
|
@ -214,14 +233,6 @@ mod tests {
|
|||
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;
|
||||
|
@ -229,10 +240,15 @@ mod tests {
|
|||
}
|
||||
|
||||
register_and_signin(NAME, EMAIL, PASSWORD).await;
|
||||
let (data, _, signin_resp) = add_token_util(NAME, PASSWORD, DOMAIN, TOKEN_NAME).await;
|
||||
let (data, _, signin_resp, key) = add_token_util(NAME, PASSWORD).await;
|
||||
let cookies = get_cookie!(signin_resp);
|
||||
let mut app = get_app!(data).await;
|
||||
|
||||
let add_level = AddLevels {
|
||||
levels: levels.clone(),
|
||||
key: key.key.clone(),
|
||||
};
|
||||
|
||||
// 1. add level
|
||||
let add_token_resp = test::call_service(
|
||||
&mut app,
|
||||
|
@ -246,7 +262,7 @@ mod tests {
|
|||
// 2. get level
|
||||
let get_level_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get_level, GET_URL)
|
||||
post_request!(&key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
@ -268,7 +284,7 @@ mod tests {
|
|||
let levels = vec![l1, l2];
|
||||
let add_level = AddLevels {
|
||||
levels: levels.clone(),
|
||||
name: TOKEN_NAME.into(),
|
||||
key: key.key.clone(),
|
||||
};
|
||||
let add_token_resp = test::call_service(
|
||||
&mut app,
|
||||
|
@ -280,7 +296,7 @@ mod tests {
|
|||
assert_eq!(add_token_resp.status(), StatusCode::OK);
|
||||
let get_level_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get_level, GET_URL)
|
||||
post_request!(&key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
@ -301,7 +317,7 @@ mod tests {
|
|||
let levels = vec![l1, l2];
|
||||
let add_level = AddLevels {
|
||||
levels: levels.clone(),
|
||||
name: TOKEN_NAME.into(),
|
||||
key: key.key.clone(),
|
||||
};
|
||||
let add_token_resp = test::call_service(
|
||||
&mut app,
|
||||
|
@ -313,7 +329,7 @@ mod tests {
|
|||
assert_eq!(add_token_resp.status(), StatusCode::OK);
|
||||
let get_level_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get_level, GET_URL)
|
||||
post_request!(&key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
use actix_identity::Identity;
|
||||
use actix_web::{post, web, HttpResponse, Responder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use super::{get_random, is_authenticated};
|
||||
use crate::errors::*;
|
||||
|
@ -26,68 +25,58 @@ use crate::Data;
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct MCaptchaID {
|
||||
pub name: String,
|
||||
pub domain: String,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct MCaptchaDetails {
|
||||
pub name: String,
|
||||
pub name: Option<String>,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/add")]
|
||||
pub async fn add_mcaptcha(
|
||||
payload: web::Json<MCaptchaID>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
#[post("/api/v1/mcaptcha/add")]
|
||||
pub async fn add_mcaptcha(data: web::Data<Data>, id: Identity) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
let key = get_random(32);
|
||||
let url = Url::parse(&payload.domain)?;
|
||||
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
let res = sqlx::query!(
|
||||
"INSERT INTO mcaptcha_config
|
||||
(name, key, domain_name)
|
||||
VALUES ($1, $2, (
|
||||
SELECT name FROM mcaptcha_domains_verified WHERE name = ($3)))",
|
||||
&payload.name,
|
||||
(key, user_id)
|
||||
VALUES ($1, (SELECT ID FROM mcaptcha_users WHERE name = $2))",
|
||||
&key,
|
||||
&host,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Err(e) => Err(dup_error(e, ServiceError::TokenNameTaken)),
|
||||
Err(e) => {
|
||||
println!("{}", &e);
|
||||
Err(dup_error(e, ServiceError::TokenNameTaken))
|
||||
}
|
||||
Ok(_) => {
|
||||
let resp = MCaptchaDetails {
|
||||
key,
|
||||
name: payload.into_inner().name,
|
||||
};
|
||||
|
||||
let resp = MCaptchaDetails { key, name: None };
|
||||
Ok(HttpResponse::Ok().json(resp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/update")]
|
||||
#[post("/api/v1/mcaptcha/update/key")]
|
||||
pub async fn update_token(
|
||||
payload: web::Json<MCaptchaID>,
|
||||
payload: web::Json<MCaptchaDetails>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
use std::borrow::Cow;
|
||||
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.domain)?;
|
||||
let username = id.identity().unwrap();
|
||||
let mut key;
|
||||
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
loop {
|
||||
key = get_random(32);
|
||||
let res = update_token_helper(&key, &payload.name, &host, &data).await;
|
||||
let res = update_token_helper(&key, &payload.key, &username, &data).await;
|
||||
if res.is_ok() {
|
||||
break;
|
||||
} else {
|
||||
|
@ -111,37 +100,36 @@ pub async fn update_token(
|
|||
|
||||
async fn update_token_helper(
|
||||
key: &str,
|
||||
name: &str,
|
||||
host: &str,
|
||||
old_key: &str,
|
||||
username: &str,
|
||||
data: &Data,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"UPDATE mcaptcha_config SET key = $1
|
||||
WHERE name = $2 AND domain_name = $3",
|
||||
WHERE key = $2 AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = $3)",
|
||||
&key,
|
||||
&name,
|
||||
&host,
|
||||
&old_key,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/get")]
|
||||
#[post("/api/v1/mcaptcha/get")]
|
||||
pub async fn get_token(
|
||||
payload: web::Json<MCaptchaID>,
|
||||
payload: web::Json<MCaptchaDetails>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let url = Url::parse(&payload.domain)?;
|
||||
|
||||
let host = url.host_str().ok_or(ServiceError::NotAUrl)?;
|
||||
let username = id.identity().unwrap();
|
||||
let res = match sqlx::query_as!(
|
||||
MCaptchaDetails,
|
||||
"SELECT key, name from mcaptcha_config WHERE name = $1 AND domain_name = $2",
|
||||
&payload.name,
|
||||
&host,
|
||||
"SELECT key, name from mcaptcha_config
|
||||
WHERE key = ($1) AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = $2) ",
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.fetch_one(&data.db)
|
||||
.await
|
||||
|
@ -157,16 +145,20 @@ pub async fn get_token(
|
|||
Ok(HttpResponse::Ok().json(res))
|
||||
}
|
||||
|
||||
#[post("/api/v1/mcaptcha/domain/token/delete")]
|
||||
#[post("/api/v1/mcaptcha/delete")]
|
||||
pub async fn delete_mcaptcha(
|
||||
payload: web::Json<MCaptchaID>,
|
||||
payload: web::Json<MCaptchaDetails>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
let username = id.identity().unwrap();
|
||||
|
||||
sqlx::query!(
|
||||
"DELETE FROM mcaptcha_config WHERE name = ($1)",
|
||||
&payload.name,
|
||||
"DELETE FROM mcaptcha_config
|
||||
WHERE key = ($1) AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = $2) ",
|
||||
&payload.key,
|
||||
&username,
|
||||
)
|
||||
.execute(&data.db)
|
||||
.await?;
|
||||
|
@ -197,10 +189,8 @@ mod tests {
|
|||
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";
|
||||
const ADD_URL: &str = "/api/v1/mcaptcha/add";
|
||||
const DEL_URL: &str = "/api/v1/mcaptcha/delete";
|
||||
|
||||
{
|
||||
let data = Data::new().await;
|
||||
|
@ -209,42 +199,18 @@ mod tests {
|
|||
|
||||
// 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 (data, _, signin_resp, token_key) = add_token_util(NAME, PASSWORD).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;
|
||||
// let mut domain = MCaptchaID {
|
||||
// name: TOKEN_NAME.into(),
|
||||
// };
|
||||
|
||||
// 4. delete token
|
||||
let del_token = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, DEL_URL)
|
||||
post_request!(&token_key, DEL_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
@ -257,10 +223,8 @@ mod tests {
|
|||
const NAME: &str = "updateusermcaptcha";
|
||||
const PASSWORD: &str = "longpassworddomain";
|
||||
const EMAIL: &str = "testupdateusermcaptcha@a.com";
|
||||
const DOMAIN: &str = "http://update-mcaptcha.example.com";
|
||||
const TOKEN_NAME: &str = "get_update_mcaptcha_works_token";
|
||||
const UPDATE_URL: &str = "/api/v1/mcaptcha/domain/token/update";
|
||||
const GET_URL: &str = "/api/v1/mcaptcha/domain/token/get";
|
||||
const UPDATE_URL: &str = "/api/v1/mcaptcha/update/key";
|
||||
const GET_URL: &str = "/api/v1/mcaptcha/get";
|
||||
|
||||
{
|
||||
let data = Data::new().await;
|
||||
|
@ -269,18 +233,14 @@ mod tests {
|
|||
|
||||
// 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 (data, _, signin_resp, token_key) = add_token_util(NAME, PASSWORD).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. update token key
|
||||
let update_token_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, UPDATE_URL)
|
||||
post_request!(&token_key, UPDATE_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
@ -288,22 +248,25 @@ mod tests {
|
|||
assert_eq!(update_token_resp.status(), StatusCode::OK);
|
||||
let updated_token: MCaptchaDetails = test::read_body_json(update_token_resp).await;
|
||||
|
||||
// get token key with updated key
|
||||
let get_token_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, GET_URL)
|
||||
post_request!(&updated_token, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(get_token_resp.status(), StatusCode::OK);
|
||||
let get_token_key: MCaptchaDetails = test::read_body_json(get_token_resp).await;
|
||||
|
||||
// check if they match
|
||||
let mut get_token_key: MCaptchaDetails = test::read_body_json(get_token_resp).await;
|
||||
assert_eq!(get_token_key.key, updated_token.key);
|
||||
|
||||
domain.name = "https://batsense.net".into();
|
||||
get_token_key.key = "nonexistent".into();
|
||||
|
||||
let get_nonexistent_token_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, GET_URL)
|
||||
post_request!(&get_token_key, GET_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pub mod domains;
|
||||
pub mod duration;
|
||||
pub mod levels;
|
||||
pub mod mcaptcha;
|
||||
|
|
|
@ -34,13 +34,6 @@ pub fn services(cfg: &mut ServiceConfig) {
|
|||
cfg.service(auth::username_exists);
|
||||
cfg.service(auth::email_exists);
|
||||
|
||||
// mcaptcha
|
||||
// domain
|
||||
cfg.service(mcaptcha::domains::add_domain);
|
||||
cfg.service(mcaptcha::domains::delete_domain);
|
||||
cfg.service(mcaptcha::domains::verify);
|
||||
cfg.service(mcaptcha::domains::get_challenge);
|
||||
|
||||
// mcaptcha
|
||||
cfg.service(mcaptcha::mcaptcha::add_mcaptcha);
|
||||
cfg.service(mcaptcha::mcaptcha::delete_mcaptcha);
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use log::info;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use actix_web::{dev::Server, middleware, web, App, HttpResponse, HttpServer, Responder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/*
|
||||
* Simple KV Server that stores a json of with schema
|
||||
* `Challenge` at path /{key}/ on POST and emits on GET
|
||||
*/
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Challenge {
|
||||
verification_challenge: String,
|
||||
}
|
||||
|
||||
pub async fn server(ip: &str, tx: mpsc::Sender<Server>) {
|
||||
pretty_env_logger::init();
|
||||
let srv = HttpServer::new(move || {
|
||||
let store: UtilKVServer = Arc::new(RwLock::new(HashMap::new()));
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
.wrap(middleware::NormalizePath::default())
|
||||
.data(store)
|
||||
.route("/{key}/", web::post().to(util_server_add))
|
||||
.route("/{key}/", web::get().to(util_server_retrive))
|
||||
})
|
||||
.bind(ip)
|
||||
.unwrap()
|
||||
.run();
|
||||
|
||||
tx.send(srv.clone()).unwrap();
|
||||
}
|
||||
|
||||
type UtilKVServer = Arc<RwLock<HashMap<String, Challenge>>>;
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
async fn util_server_retrive(
|
||||
key: web::Path<String>,
|
||||
data: web::Data<UtilKVServer>,
|
||||
) -> impl Responder {
|
||||
let key = key.into_inner();
|
||||
let store = data.read().unwrap();
|
||||
let resp = store.get(&key).unwrap();
|
||||
info!("[kv-server] retrive: key :{}, value: {:?}", key, resp);
|
||||
HttpResponse::Ok().json(resp)
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
async fn util_server_add(
|
||||
key: web::Path<String>,
|
||||
payload: web::Json<Challenge>,
|
||||
data: web::Data<UtilKVServer>,
|
||||
) -> impl Responder {
|
||||
info!("[kv-server] cache: key :{}, value: {:?}", key, payload);
|
||||
let mut store = data.write().unwrap();
|
||||
store.insert(key.into_inner(), payload.into_inner());
|
||||
HttpResponse::Ok()
|
||||
}
|
|
@ -16,6 +16,3 @@
|
|||
*/
|
||||
|
||||
mod auth;
|
||||
mod kvserver;
|
||||
|
||||
pub use kvserver::server;
|
||||
|
|
127
src/tests/mod.rs
127
src/tests/mod.rs
|
@ -7,6 +7,7 @@ use serde::Serialize;
|
|||
|
||||
use super::*;
|
||||
use crate::api::v1::auth::{Login, Register};
|
||||
use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails;
|
||||
use crate::api::v1::services as v1_services;
|
||||
use crate::data::Data;
|
||||
use crate::errors::*;
|
||||
|
@ -30,6 +31,10 @@ pub async fn delete_user(name: &str, data: &Data) {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! post_request {
|
||||
($uri:expr) => {
|
||||
test::TestRequest::post().uri($uri)
|
||||
};
|
||||
|
||||
($serializable:expr, $uri:expr) => {
|
||||
test::TestRequest::post()
|
||||
.uri($uri)
|
||||
|
@ -96,79 +101,81 @@ pub async fn signin<'a>(name: &'a str, password: &str) -> (data::Data, Login, Se
|
|||
(data, creds, signin_resp)
|
||||
}
|
||||
|
||||
/// register and signin and domain
|
||||
/// bypasses domain verification, use with care
|
||||
pub async fn add_domain_util(
|
||||
///// 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,
|
||||
domain: &str,
|
||||
) -> (data::Data, Login, ServiceResponse) {
|
||||
use crate::api::v1::mcaptcha::domains::Domain;
|
||||
use url::Url;
|
||||
) -> (data::Data, Login, ServiceResponse, MCaptchaDetails) {
|
||||
// use crate::api::v1::mcaptcha::mcaptcha::MCaptchaID;
|
||||
|
||||
const ADD_URL: &str = "/api/v1/mcaptcha/add";
|
||||
|
||||
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,
|
||||
domain: &str,
|
||||
token_name: &str,
|
||||
) -> (data::Data, Login, ServiceResponse) {
|
||||
use crate::api::v1::mcaptcha::mcaptcha::MCaptchaID;
|
||||
|
||||
const ADD_URL: &str = "/api/v1/mcaptcha/domain/token/add";
|
||||
|
||||
let (data, creds, signin_resp) = add_domain_util(name, password, domain).await;
|
||||
let cookies = get_cookie!(signin_resp);
|
||||
let mut app = get_app!(data).await;
|
||||
|
||||
// 1. add mcaptcha token
|
||||
let domain = MCaptchaID {
|
||||
domain: domain.into(),
|
||||
name: token_name.into(),
|
||||
};
|
||||
// // 1. add mcaptcha token
|
||||
// let domain = MCaptchaID {
|
||||
// name: token_name.into(),
|
||||
// };
|
||||
let add_token_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&domain, ADD_URL)
|
||||
.cookie(cookies.clone())
|
||||
.to_request(),
|
||||
post_request!(ADD_URL).cookie(cookies.clone()).to_request(),
|
||||
)
|
||||
.await;
|
||||
// let status = add_token_resp.status();
|
||||
// let txt: ErrorToResponse = test::read_body_json(add_token_resp).await;
|
||||
// println!("{:?}", txt.error);
|
||||
//
|
||||
assert_eq!(add_token_resp.status(), StatusCode::OK);
|
||||
let token_key: MCaptchaDetails = test::read_body_json(add_token_resp).await;
|
||||
|
||||
(data, creds, signin_resp)
|
||||
// assert_eq!(status, StatusCode::OK);
|
||||
|
||||
(data, creds, signin_resp, token_key)
|
||||
}
|
||||
|
||||
/// pub duplicate test
|
||||
|
|
Loading…
Add table
Reference in a new issue