mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2026-02-11 01:55:40 +00:00
del user, add del domains
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -415,7 +415,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "argon2-creds"
|
name = "argon2-creds"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/realaravinth/argon2-creds?tag=0.2.0#1934a6cc1b1fd4b9583da2ea6862f176c03cbfb6"
|
source = "git+https://github.com/realaravinth/argon2-creds#61f2d1d5a2660905939054f6be03e76584965b63"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
@@ -426,7 +426,6 @@ dependencies = [
|
|||||||
"rust-argon2",
|
"rust-argon2",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
"validator",
|
"validator",
|
||||||
"validator_derive",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1861,7 +1860,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "pow_sha256"
|
name = "pow_sha256"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/mcaptcha/pow_sha256#d0889fc9008e63795b024b57432ed0034a703d0b"
|
source = "git+https://github.com/mcaptcha/pow_sha256#1b65c603bdd527e3e1f3b8b565a11fcde48575b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
@@ -2930,6 +2929,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url",
|
"url",
|
||||||
|
"validator_derive",
|
||||||
"validator_types",
|
"validator_types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ actix-web = "3"
|
|||||||
actix = "0.10"
|
actix = "0.10"
|
||||||
|
|
||||||
sqlx = { version = "0.4.0", features = [ "runtime-actix-rustls", "postgres" ] }
|
sqlx = { version = "0.4.0", features = [ "runtime-actix-rustls", "postgres" ] }
|
||||||
argon2-creds = { version = "0.2", git = "https://github.com/realaravinth/argon2-creds", tag = "0.2.0" }
|
argon2-creds = { version = "0.2", git = "https://github.com/realaravinth/argon2-creds", commit = "61f2d1d" }
|
||||||
|
|
||||||
config = "0.10"
|
config = "0.10"
|
||||||
validator = "0.12"
|
validator = { version = "0.12", features = ["derive"]}
|
||||||
|
|
||||||
derive_builder = "0.9"
|
derive_builder = "0.9"
|
||||||
derive_more = "0.99"
|
derive_more = "0.99"
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::Data;
|
use crate::Data;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub struct SomeData {
|
|
||||||
pub a: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Register {
|
pub struct Register {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
@@ -104,16 +99,55 @@ pub async fn signout(id: Identity) -> impl Responder {
|
|||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_authenticated(id: &Identity) -> ServiceResult<bool> {
|
/// Check if user is authenticated
|
||||||
debug!("{:?}", id.identity());
|
// TODO use middleware
|
||||||
|
pub fn is_authenticated(id: &Identity) -> ServiceResult<()> {
|
||||||
// access request identity
|
// access request identity
|
||||||
if let Some(_) = id.identity() {
|
if let Some(_) = id.identity() {
|
||||||
Ok(true)
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ServiceError::AuthorizationRequired)
|
Err(ServiceError::AuthorizationRequired)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/api/v1/account/delete")]
|
||||||
|
pub async fn delete_account(
|
||||||
|
id: Identity,
|
||||||
|
payload: web::Json<Login>,
|
||||||
|
data: web::Data<Data>,
|
||||||
|
) -> ServiceResult<impl Responder> {
|
||||||
|
use argon2_creds::Config;
|
||||||
|
use sqlx::Error::RowNotFound;
|
||||||
|
|
||||||
|
is_authenticated(&id)?;
|
||||||
|
|
||||||
|
let rec = sqlx::query_as!(
|
||||||
|
Password,
|
||||||
|
r#"SELECT password FROM mcaptcha_users WHERE name = ($1)"#,
|
||||||
|
&payload.username,
|
||||||
|
)
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match rec {
|
||||||
|
Ok(s) => {
|
||||||
|
if Config::verify(&s.password, &payload.password)? {
|
||||||
|
sqlx::query!(
|
||||||
|
"DELETE FROM mcaptcha_users WHERE name = ($1)",
|
||||||
|
&payload.username,
|
||||||
|
)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok())
|
||||||
|
} else {
|
||||||
|
Err(ServiceError::WrongPassword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(RowNotFound) => return Err(ServiceError::UsernameNotFound),
|
||||||
|
Err(_) => return Err(ServiceError::InternalServerError)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use actix_web::http::{header, StatusCode};
|
use actix_web::http::{header, StatusCode};
|
||||||
@@ -124,34 +158,7 @@ mod tests {
|
|||||||
use crate::data::Data;
|
use crate::data::Data;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub async fn delete_user(name: &str, data: &Data) {
|
use crate::tests::*;
|
||||||
let _ = sqlx::query!("DELETE FROM mcaptcha_users WHERE name = ($1)", name,)
|
|
||||||
.execute(&data.db)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! post_request {
|
|
||||||
($serializable:expr, $uri:expr) => {
|
|
||||||
test::TestRequest::post()
|
|
||||||
.uri($uri)
|
|
||||||
.header(header::CONTENT_TYPE, "application/json")
|
|
||||||
.set_payload(serde_json::to_string($serializable).unwrap())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! get_server {
|
|
||||||
() => {
|
|
||||||
App::new()
|
|
||||||
.wrap(middleware::Logger::default())
|
|
||||||
.wrap(get_identity_service())
|
|
||||||
.wrap(middleware::Compress::default())
|
|
||||||
.wrap(middleware::NormalizePath::new(
|
|
||||||
middleware::normalize::TrailingSlash::Trim,
|
|
||||||
))
|
|
||||||
.app_data(get_json_err())
|
|
||||||
.configure(v1_services)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn auth_works() {
|
async fn auth_works() {
|
||||||
@@ -160,39 +167,25 @@ mod tests {
|
|||||||
const PASSWORD: &str = "longpassword";
|
const PASSWORD: &str = "longpassword";
|
||||||
const EMAIL: &str = "testuser1@a.com";
|
const EMAIL: &str = "testuser1@a.com";
|
||||||
|
|
||||||
let mut app = test::init_service(get_server!().data(data.clone())).await;
|
let mut app = get_app!(data).await;
|
||||||
|
|
||||||
delete_user(NAME, &data).await;
|
delete_user(NAME, &data).await;
|
||||||
|
|
||||||
// 1. Register
|
// 1. Register and signin
|
||||||
|
let (data, _, signin_resp) = signin_util(NAME, EMAIL, PASSWORD).await;
|
||||||
|
let cookies = get_cookie!(signin_resp);
|
||||||
|
|
||||||
|
// 2. check if duplicate username is allowed
|
||||||
let msg = Register {
|
let msg = Register {
|
||||||
username: NAME.into(),
|
username: NAME.into(),
|
||||||
password: PASSWORD.into(),
|
password: PASSWORD.into(),
|
||||||
email: EMAIL.into(),
|
email: EMAIL.into(),
|
||||||
};
|
};
|
||||||
let resp =
|
|
||||||
test::call_service(&mut app, post_request!(&msg, "/api/v1/signup").to_request()).await;
|
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
|
||||||
|
|
||||||
// 2. check if duplicate username is allowed
|
|
||||||
let duplicate_user_resp =
|
let duplicate_user_resp =
|
||||||
test::call_service(&mut app, post_request!(&msg, "/api/v1/signup").to_request()).await;
|
test::call_service(&mut app, post_request!(&msg, "/api/v1/signup").to_request()).await;
|
||||||
assert_eq!(duplicate_user_resp.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(duplicate_user_resp.status(), StatusCode::BAD_REQUEST);
|
||||||
|
|
||||||
// 3. signin
|
// 3. sigining in with non-existent user
|
||||||
let sigin_msg = Login {
|
|
||||||
username: NAME.into(),
|
|
||||||
password: PASSWORD.into(),
|
|
||||||
};
|
|
||||||
let signin_resp = test::call_service(
|
|
||||||
&mut app,
|
|
||||||
post_request!(&sigin_msg, "/api/v1/signin").to_request(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
assert_eq!(signin_resp.status(), StatusCode::OK);
|
|
||||||
let cookies = signin_resp.response().cookies().next().unwrap().to_owned();
|
|
||||||
|
|
||||||
// 4. sigining in with non-existent user
|
|
||||||
let nonexistantuser = Login {
|
let nonexistantuser = Login {
|
||||||
username: "nonexistantuser".into(),
|
username: "nonexistantuser".into(),
|
||||||
password: msg.password.clone(),
|
password: msg.password.clone(),
|
||||||
@@ -206,7 +199,7 @@ mod tests {
|
|||||||
let txt: ErrorToResponse = test::read_body_json(userdoesntexist).await;
|
let txt: ErrorToResponse = test::read_body_json(userdoesntexist).await;
|
||||||
assert_eq!(txt.error, format!("{}", ServiceError::UsernameNotFound));
|
assert_eq!(txt.error, format!("{}", ServiceError::UsernameNotFound));
|
||||||
|
|
||||||
// 5. trying to signin with wrong password
|
// 4. trying to signin with wrong password
|
||||||
let wrongpassword = Login {
|
let wrongpassword = Login {
|
||||||
username: NAME.into(),
|
username: NAME.into(),
|
||||||
password: NAME.into(),
|
password: NAME.into(),
|
||||||
@@ -220,7 +213,7 @@ mod tests {
|
|||||||
let txt: ErrorToResponse = test::read_body_json(wrongpassword_resp).await;
|
let txt: ErrorToResponse = test::read_body_json(wrongpassword_resp).await;
|
||||||
assert_eq!(txt.error, format!("{}", ServiceError::WrongPassword));
|
assert_eq!(txt.error, format!("{}", ServiceError::WrongPassword));
|
||||||
|
|
||||||
// 6. signout
|
// 5. signout
|
||||||
let signout_resp = test::call_service(
|
let signout_resp = test::call_service(
|
||||||
&mut app,
|
&mut app,
|
||||||
post_request!(&wrongpassword, "/api/v1/signout")
|
post_request!(&wrongpassword, "/api/v1/signout")
|
||||||
@@ -232,4 +225,26 @@ mod tests {
|
|||||||
|
|
||||||
delete_user(NAME, &data).await;
|
delete_user(NAME, &data).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn del_userworks() {
|
||||||
|
const NAME: &str = "testuser2";
|
||||||
|
const PASSWORD: &str = "longpassword2";
|
||||||
|
const EMAIL: &str = "testuser1@a.com2";
|
||||||
|
|
||||||
|
let (data, creds, signin_resp) = signin_util(NAME, EMAIL, PASSWORD).await;
|
||||||
|
let cookies = get_cookie!(signin_resp);
|
||||||
|
let mut app = get_app!(data).await;
|
||||||
|
|
||||||
|
let delete_user_resp = test::call_service(
|
||||||
|
&mut app,
|
||||||
|
post_request!(&creds, "/api/v1/account/delete")
|
||||||
|
.cookie(cookies)
|
||||||
|
.to_request(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_eq!(delete_user_resp.status(), StatusCode::OK);
|
||||||
|
delete_user(NAME, &data).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
116
src/api/v1/mcaptcha.rs
Normal file
116
src/api/v1/mcaptcha.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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::{post, web, HttpResponse, Responder};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use super::auth::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)?;
|
||||||
|
if let Some(host) = url.host_str() {
|
||||||
|
sqlx::query!("INSERT INTO mcaptcha_domains (name) VALUES ($1)", host,)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok())
|
||||||
|
} else {
|
||||||
|
Err(ServiceError::NotAUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)?;
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 = "testuserdomain";
|
||||||
|
const PASSWORD: &str = "longpassworddomain";
|
||||||
|
const EMAIL: &str = "testuserdomain@a.com";
|
||||||
|
const DOMAIN: &str = "http://example.com";
|
||||||
|
|
||||||
|
let (data, _, signin_resp) = signin_util(NAME, EMAIL, PASSWORD).await;
|
||||||
|
let cookies = get_cookie!(signin_resp);
|
||||||
|
let mut app = get_app!(data).await;
|
||||||
|
|
||||||
|
delete_domain_util(DOMAIN, &data).await;
|
||||||
|
|
||||||
|
// 1. add domain
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 2. 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);
|
||||||
|
delete_user(NAME, &data).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,10 +18,17 @@
|
|||||||
use actix_web::web::ServiceConfig;
|
use actix_web::web::ServiceConfig;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod mcaptcha;
|
||||||
|
|
||||||
pub fn services(cfg: &mut ServiceConfig) {
|
pub fn services(cfg: &mut ServiceConfig) {
|
||||||
use auth::*;
|
use auth::*;
|
||||||
|
use mcaptcha::*;
|
||||||
|
|
||||||
cfg.service(signout);
|
cfg.service(signout);
|
||||||
cfg.service(signin);
|
cfg.service(signin);
|
||||||
cfg.service(signup);
|
cfg.service(signup);
|
||||||
|
cfg.service(delete_account);
|
||||||
|
|
||||||
|
cfg.service(add_domain);
|
||||||
|
cfg.service(delete_domain);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ use actix_web::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use argon2_creds::errors::CredsError;
|
use argon2_creds::errors::CredsError;
|
||||||
|
use url::ParseError;
|
||||||
|
|
||||||
use derive_more::{Display, Error};
|
use derive_more::{Display, Error};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// use validator::ValidationErrors;
|
use validator::ValidationErrors;
|
||||||
|
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
|
||||||
@@ -67,6 +68,8 @@ pub enum ServiceError {
|
|||||||
PasswordTooShort,
|
PasswordTooShort,
|
||||||
#[display(fmt = "Username too long")]
|
#[display(fmt = "Username too long")]
|
||||||
PasswordTooLong,
|
PasswordTooLong,
|
||||||
|
#[display(fmt = "The value you entered for URL is not a URL")] //405j
|
||||||
|
NotAUrl,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -91,6 +94,7 @@ impl ResponseError for ServiceError {
|
|||||||
match *self {
|
match *self {
|
||||||
ServiceError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
ServiceError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
ServiceError::NotAnEmail => StatusCode::BAD_REQUEST,
|
ServiceError::NotAnEmail => StatusCode::BAD_REQUEST,
|
||||||
|
ServiceError::NotAUrl => StatusCode::BAD_REQUEST,
|
||||||
ServiceError::WrongPassword => StatusCode::UNAUTHORIZED,
|
ServiceError::WrongPassword => StatusCode::UNAUTHORIZED,
|
||||||
ServiceError::UsernameNotFound => StatusCode::UNAUTHORIZED,
|
ServiceError::UsernameNotFound => StatusCode::UNAUTHORIZED,
|
||||||
ServiceError::AuthorizationRequired => StatusCode::UNAUTHORIZED,
|
ServiceError::AuthorizationRequired => StatusCode::UNAUTHORIZED,
|
||||||
@@ -120,12 +124,17 @@ impl From<CredsError> for ServiceError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl From<ValidationErrors> for ServiceError {
|
impl From<ValidationErrors> for ServiceError {
|
||||||
// fn from(_: ValidationErrors) -> ServiceError {
|
fn from(_: ValidationErrors) -> ServiceError {
|
||||||
// ServiceError::NotAnEmail
|
ServiceError::NotAnEmail
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
|
impl From<ParseError> for ServiceError {
|
||||||
|
fn from(_: ParseError) -> ServiceError {
|
||||||
|
ServiceError::NotAUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
impl From<sqlx::Error> for ServiceError {
|
impl From<sqlx::Error> for ServiceError {
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ mod errors;
|
|||||||
//mod routes;
|
//mod routes;
|
||||||
mod api;
|
mod api;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
pub use data::Data;
|
pub use data::Data;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ mod settings;
|
|||||||
pub use data::Data;
|
pub use data::Data;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
lazy_static! {
|
||||||
|
#[cfg(not(tarpaulin_include))]
|
||||||
pub static ref SETTINGS: Settings = Settings::new().unwrap();
|
pub static ref SETTINGS: Settings = Settings::new().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
src/tests/mod.rs
Normal file
87
src/tests/mod.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use actix_web::test;
|
||||||
|
use actix_web::{
|
||||||
|
dev::ServiceResponse,
|
||||||
|
http::{header, StatusCode},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::api::v1::auth::{Login, Register};
|
||||||
|
use crate::api::v1::services as v1_services;
|
||||||
|
use crate::data::Data;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! get_cookie {
|
||||||
|
($resp:expr) => {
|
||||||
|
$resp.response().cookies().next().unwrap().to_owned()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_user(name: &str, data: &Data) {
|
||||||
|
let _ = sqlx::query!("DELETE FROM mcaptcha_users WHERE name = ($1)", name,)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_domain_util(name: &str, data: &Data) {
|
||||||
|
let _ = sqlx::query!("DELETE FROM mcaptcha_domains WHERE name = ($1)", name,)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! post_request {
|
||||||
|
($serializable:expr, $uri:expr) => {
|
||||||
|
test::TestRequest::post()
|
||||||
|
.uri($uri)
|
||||||
|
.header(header::CONTENT_TYPE, "application/json")
|
||||||
|
.set_payload(serde_json::to_string($serializable).unwrap())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! get_app {
|
||||||
|
($data:expr) => {
|
||||||
|
test::init_service(
|
||||||
|
App::new()
|
||||||
|
.wrap(get_identity_service())
|
||||||
|
.configure(v1_services)
|
||||||
|
.data($data.clone()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// register and signin utility
|
||||||
|
pub async fn signin_util<'a>(
|
||||||
|
name: &'a str,
|
||||||
|
email: &str,
|
||||||
|
password: &str,
|
||||||
|
) -> (data::Data, Login, ServiceResponse) {
|
||||||
|
let data = Data::new().await;
|
||||||
|
let mut app = get_app!(data).await;
|
||||||
|
|
||||||
|
delete_user(&name, &data).await;
|
||||||
|
|
||||||
|
// 1. Register
|
||||||
|
let msg = Register {
|
||||||
|
username: name.into(),
|
||||||
|
password: password.into(),
|
||||||
|
email: email.into(),
|
||||||
|
};
|
||||||
|
let resp =
|
||||||
|
test::call_service(&mut app, post_request!(&msg, "/api/v1/signup").to_request()).await;
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
|
// 2. signin
|
||||||
|
let creds = Login {
|
||||||
|
username: name.into(),
|
||||||
|
password: password.into(),
|
||||||
|
};
|
||||||
|
let signin_resp = test::call_service(
|
||||||
|
&mut app,
|
||||||
|
post_request!(&creds, "/api/v1/signin").to_request(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(signin_resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
|
(data, creds, signin_resp)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user