mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2025-03-14 13:08:27 +03:00
pow verification
This commit is contained in:
parent
e76dd8014c
commit
7777db477e
9 changed files with 173 additions and 27 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -521,11 +521,10 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.2"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde 1.0.125",
|
||||
]
|
||||
|
||||
|
@ -601,9 +600,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
|||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
|
@ -629,7 +628,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cache-buster"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/realaravinth/cache-buster#26d40b9993820837aa9d2d683937e502bfd3be12"
|
||||
source = "git+https://github.com/realaravinth/cache-buster#71d5ef67a2788789922eaa484e10269acbaeb8a7"
|
||||
dependencies = [
|
||||
"data-encoding",
|
||||
"derive_builder 0.10.0",
|
||||
|
@ -1295,6 +1294,7 @@ dependencies = [
|
|||
"m_captcha",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"pow_sha256",
|
||||
"pretty_env_logger",
|
||||
"rand 0.8.3",
|
||||
"rust-embed",
|
||||
|
@ -1611,7 +1611,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "m_captcha"
|
||||
version = "0.1.3"
|
||||
source = "git+https://github.com/mCaptcha/mCaptcha?branch=master#2d120d6791d8a32e7b3e31a7c5f1b54e3b35f9ef"
|
||||
source = "git+https://github.com/mCaptcha/mCaptcha?branch=master#29cd8f4fd83a3646a48ca2c9f5563d8d5360d2c3"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"derive_builder 0.9.0",
|
||||
|
|
|
@ -67,3 +67,6 @@ serde_json = "1"
|
|||
yaml-rust = "0.4.5"
|
||||
cache-buster = { version = "0.1", git = "https://github.com/realaravinth/cache-buster" }
|
||||
mime = "0.3.16"
|
||||
|
||||
[dev-dependencies]
|
||||
pow_sha256 = { version = "0.2.1", git = "https://github.com/mcaptcha/pow_sha256" }
|
||||
|
|
3
build.rs
3
build.rs
|
@ -55,6 +55,5 @@ fn cache_bust() {
|
|||
.build()
|
||||
.unwrap();
|
||||
|
||||
config.init().unwrap();
|
||||
config.hash().unwrap().to_env();
|
||||
config.process().unwrap().to_env();
|
||||
}
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
*/
|
||||
|
||||
use actix::prelude::*;
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{post, web, HttpResponse, Responder};
|
||||
use m_captcha::{defense::LevelBuilder, master::AddSiteBuilder, DefenseBuilder, MCaptchaBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::duration::GetDurationResp;
|
||||
use super::is_authenticated;
|
||||
use super::levels::I32Levels;
|
||||
use super::GetDurationResp;
|
||||
use super::I32Levels;
|
||||
use crate::errors::*;
|
||||
use crate::Data;
|
||||
|
||||
|
@ -44,10 +42,7 @@ pub struct GetConfigPayload {
|
|||
pub async fn get_config(
|
||||
payload: web::Json<GetConfigPayload>,
|
||||
data: web::Data<Data>,
|
||||
id: Identity,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
is_authenticated(&id)?;
|
||||
|
||||
let res = sqlx::query!(
|
||||
"SELECT EXISTS (SELECT 1 from mcaptcha_config WHERE key = $1)",
|
||||
&payload.key,
|
23
src/api/v1/mcaptcha/pow/mod.rs
Normal file
23
src/api/v1/mcaptcha/pow/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
pub mod get_config;
|
||||
pub mod verify_pow;
|
||||
|
||||
pub use super::duration::GetDurationResp;
|
||||
pub use super::is_authenticated;
|
||||
pub use super::levels::I32Levels;
|
0
src/api/v1/mcaptcha/pow/verifiy_token.rs
Normal file
0
src/api/v1/mcaptcha/pow/verifiy_token.rs
Normal file
135
src/api/v1/mcaptcha/pow/verify_pow.rs
Normal file
135
src/api/v1/mcaptcha/pow/verify_pow.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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_web::{post, web, HttpResponse, Responder};
|
||||
use m_captcha::pow::Work;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::Data;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct PoWConfig {
|
||||
pub name: String,
|
||||
pub domain: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct ValidationToken {
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
// API keys are mcaptcha actor names
|
||||
|
||||
#[post("/api/v1/mcaptcha/pow/verify")]
|
||||
pub async fn verify_pow(
|
||||
payload: web::Json<Work>,
|
||||
data: web::Data<Data>,
|
||||
) -> ServiceResult<impl Responder> {
|
||||
let res = data.captcha.verify_pow(payload.into_inner()).await?;
|
||||
let payload = ValidationToken { token: res };
|
||||
Ok(HttpResponse::Ok().json(payload))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::{header, StatusCode};
|
||||
use actix_web::test;
|
||||
use m_captcha::pow::PoWConfig;
|
||||
|
||||
use super::*;
|
||||
use crate::api::v1::mcaptcha::pow::get_config::GetConfigPayload;
|
||||
use crate::api::v1::services as v1_services;
|
||||
use crate::tests::*;
|
||||
use crate::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn verify_pow_works() {
|
||||
const NAME: &str = "powverifyusr";
|
||||
const PASSWORD: &str = "testingpas";
|
||||
const EMAIL: &str = "verifyuser@a.com";
|
||||
const VERIFY_URL: &str = "/api/v1/mcaptcha/pow/verify";
|
||||
const GET_URL: &str = "/api/v1/mcaptcha/pow/config";
|
||||
// const UPDATE_URL: &str = "/api/v1/mcaptcha/domain/token/duration/update";
|
||||
|
||||
{
|
||||
let data = Data::new().await;
|
||||
delete_user(NAME, &data).await;
|
||||
}
|
||||
|
||||
register_and_signin(NAME, EMAIL, PASSWORD).await;
|
||||
let (data, _, _signin_resp, token_key) = add_levels_util(NAME, PASSWORD).await;
|
||||
let mut app = get_app!(data).await;
|
||||
|
||||
let get_config_payload = GetConfigPayload {
|
||||
key: token_key.key.clone(),
|
||||
};
|
||||
|
||||
// update and check changes
|
||||
|
||||
let get_config_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get_config_payload, GET_URL).to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(get_config_resp.status(), StatusCode::OK);
|
||||
let config: PoWConfig = test::read_body_json(get_config_resp).await;
|
||||
|
||||
let pow = pow_sha256::ConfigBuilder::default()
|
||||
.salt(config.salt)
|
||||
.build()
|
||||
.unwrap();
|
||||
let work = pow
|
||||
.prove_work(&config.string.clone(), config.difficulty_factor)
|
||||
.unwrap();
|
||||
|
||||
let work = Work {
|
||||
string: config.string.clone(),
|
||||
result: work.result,
|
||||
nonce: work.nonce,
|
||||
key: token_key.key.clone(),
|
||||
};
|
||||
|
||||
let pow_verify_resp =
|
||||
test::call_service(&mut app, post_request!(&work, VERIFY_URL).to_request()).await;
|
||||
assert_eq!(pow_verify_resp.status(), StatusCode::OK);
|
||||
|
||||
let string_not_found =
|
||||
test::call_service(&mut app, post_request!(&work, VERIFY_URL).to_request()).await;
|
||||
assert_eq!(string_not_found.status(), StatusCode::BAD_REQUEST);
|
||||
let err: ErrorToResponse = test::read_body_json(string_not_found).await;
|
||||
assert_eq!(
|
||||
err.error,
|
||||
format!(
|
||||
"{}",
|
||||
ServiceError::CaptchaError(m_captcha::errors::CaptchaError::StringNotFound)
|
||||
)
|
||||
);
|
||||
|
||||
let pow_config_resp = test::call_service(
|
||||
&mut app,
|
||||
post_request!(&get_config_payload, GET_URL).to_request(),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(pow_config_resp.status(), StatusCode::OK);
|
||||
// I'm not checking for errors because changing work.result triggered
|
||||
// InssuficientDifficulty, which is possible becuase m_captcha calculates
|
||||
// difficulty with the submitted result. Besides, this endpoint is merely
|
||||
// propagating errors from m_captcha and m_captcha has tests covering the
|
||||
// pow aspects ¯\_(ツ)_/¯
|
||||
}
|
||||
}
|
|
@ -51,7 +51,8 @@ pub fn services(cfg: &mut ServiceConfig) {
|
|||
cfg.service(mcaptcha::duration::get_duration);
|
||||
|
||||
// pow
|
||||
cfg.service(mcaptcha::pow::get_config);
|
||||
cfg.service(mcaptcha::pow::get_config::get_config);
|
||||
cfg.service(mcaptcha::pow::verify_pow::verify_pow);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -76,9 +76,6 @@ pub enum ServiceError {
|
|||
/// when the a token name is already taken
|
||||
#[display(fmt = "token name not available")]
|
||||
TokenNameTaken,
|
||||
/// when the a host name is already taken
|
||||
#[display(fmt = "host name not available")]
|
||||
HostnameTaken,
|
||||
/// token not found
|
||||
#[display(fmt = "Token not found. Is token registered?")]
|
||||
TokenNotFound,
|
||||
|
@ -88,10 +85,6 @@ pub enum ServiceError {
|
|||
|
||||
#[display(fmt = "Couldn't reach your server. If Problem presists, contact support")]
|
||||
ClientServerUnreachable,
|
||||
#[display(fmt = "Couldn't parse challenge from your server. Check for courruption")]
|
||||
ChallengeCourruption,
|
||||
#[display(fmt = "Verification failure, vaules didn't match")]
|
||||
ChallengeVerificationFailure,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -132,10 +125,7 @@ impl ResponseError for ServiceError {
|
|||
|
||||
ServiceError::TokenNameTaken => StatusCode::BAD_REQUEST,
|
||||
ServiceError::TokenNotFound => StatusCode::NOT_FOUND,
|
||||
ServiceError::HostnameTaken => StatusCode::BAD_REQUEST,
|
||||
ServiceError::ClientServerUnreachable => StatusCode::SERVICE_UNAVAILABLE,
|
||||
ServiceError::ChallengeCourruption => StatusCode::BAD_REQUEST,
|
||||
ServiceError::ChallengeVerificationFailure => StatusCode::UNAUTHORIZED,
|
||||
ServiceError::CaptchaError(e) => match e {
|
||||
CaptchaError::MailboxError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
|
|
Loading…
Add table
Reference in a new issue