pow stats for solution and verification

This commit is contained in:
realaravinth
2021-05-09 19:33:28 +05:30
parent 7792d5ccc7
commit 527724ecda
7 changed files with 57 additions and 5 deletions

View File

@@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS mcaptcha_pow_solved_stats (
config_id INTEGER references mcaptcha_config(config_id) ON DELETE CASCADE,
solved_at timestamptz NOT NULL DEFAULT now()
);

View File

@@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS mcaptcha_pow_confirmed_stats (
config_id INTEGER references mcaptcha_config(config_id) ON DELETE CASCADE,
confirm_ed timestamptz NOT NULL DEFAULT now()
);

View File

@@ -17,7 +17,9 @@
use sqlx::PgPool; use sqlx::PgPool;
pub async fn fetched(key: &str, db: &PgPool) { /// record PoWConfig fetches
#[inline]
pub async fn record_fetch(key: &str, db: &PgPool) {
let _ = sqlx::query!( let _ = sqlx::query!(
"INSERT INTO mcaptcha_pow_fetched_stats "INSERT INTO mcaptcha_pow_fetched_stats
(config_id) VALUES ((SELECT config_id FROM mcaptcha_config WHERE key = $1))", (config_id) VALUES ((SELECT config_id FROM mcaptcha_config WHERE key = $1))",
@@ -26,3 +28,27 @@ pub async fn fetched(key: &str, db: &PgPool) {
.execute(db) .execute(db)
.await; .await;
} }
/// record PoWConfig solves
#[inline]
pub async fn record_solve(key: &str, db: &PgPool) {
let _ = sqlx::query!(
"INSERT INTO mcaptcha_pow_solved_stats
(config_id) VALUES ((SELECT config_id FROM mcaptcha_config WHERE key = $1))",
&key,
)
.execute(db)
.await;
}
/// record PoWConfig confirms
#[inline]
pub async fn record_confirm(key: &str, db: &PgPool) {
let _ = sqlx::query!(
"INSERT INTO mcaptcha_pow_confirmed_stats
(config_id) VALUES ((SELECT config_id FROM mcaptcha_config WHERE key = $1))",
&key,
)
.execute(db)
.await;
}

View File

@@ -20,9 +20,9 @@ use actix_web::{web, HttpResponse, Responder};
use m_captcha::{defense::LevelBuilder, master::AddSiteBuilder, DefenseBuilder, MCaptchaBuilder}; use m_captcha::{defense::LevelBuilder, master::AddSiteBuilder, DefenseBuilder, MCaptchaBuilder};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::record_fetch;
use super::GetDurationResp; use super::GetDurationResp;
use super::I32Levels; use super::I32Levels;
use crate::api::v1::mcaptcha::stats::fetched;
use crate::errors::*; use crate::errors::*;
use crate::Data; use crate::Data;
@@ -39,6 +39,7 @@ pub struct GetConfigPayload {
// API keys are mcaptcha actor names // API keys are mcaptcha actor names
/// get PoW configuration for an mcaptcha key
pub async fn get_config( pub async fn get_config(
payload: web::Json<GetConfigPayload>, payload: web::Json<GetConfigPayload>,
data: web::Data<Data>, data: web::Data<Data>,
@@ -68,7 +69,7 @@ pub async fn get_config(
.expect("mcaptcha should be initialized and ready to go"); .expect("mcaptcha should be initialized and ready to go");
// background it. would require data::Data to be static // background it. would require data::Data to be static
// to satidfy lifetime // to satidfy lifetime
fetched(&payload.key, &data.db).await; record_fetch(&payload.key, &data.db).await;
Ok(HttpResponse::Ok().json(config)) Ok(HttpResponse::Ok().json(config))
} }
} }
@@ -78,7 +79,10 @@ pub async fn get_config(
None => Err(ServiceError::TokenNotFound), None => Err(ServiceError::TokenNotFound),
} }
} }
/// Call this when [MCaptcha][m_captcha::MCaptcha] is not in master.
///
/// This fn gets mcaptcha config from database, builds [Defense][m_captcha::Defense],
/// creates [MCaptcha][m_captcha::MCaptcha] and adds it to [Master][m_captcha::Defense]
async fn init_mcaptcha(data: &Data, key: &str) -> ServiceResult<()> { async fn init_mcaptcha(data: &Data, key: &str) -> ServiceResult<()> {
// get levels // get levels
let levels_fut = sqlx::query_as!( let levels_fut = sqlx::query_as!(

View File

@@ -24,6 +24,7 @@ pub mod verify_token;
pub use super::mcaptcha::duration::GetDurationResp; pub use super::mcaptcha::duration::GetDurationResp;
pub use super::mcaptcha::levels::I32Levels; pub use super::mcaptcha::levels::I32Levels;
use crate::api::v1::mcaptcha::stats::*;
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
use crate::define_resource; use crate::define_resource;

View File

@@ -14,26 +14,34 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
//! PoW Verification module
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use m_captcha::pow::Work; use m_captcha::pow::Work;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::record_solve;
use crate::errors::*; use crate::errors::*;
use crate::Data; use crate::Data;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
/// validation token that clients receive as proof for submiting
/// valid PoW
pub struct ValidationToken { pub struct ValidationToken {
pub token: String, pub token: String,
} }
// API keys are mcaptcha actor names // API keys are mcaptcha actor names
/// route handler that verifies PoW and issues a solution token
/// if verification is successful
pub async fn verify_pow( pub async fn verify_pow(
payload: web::Json<Work>, payload: web::Json<Work>,
data: web::Data<Data>, data: web::Data<Data>,
) -> ServiceResult<impl Responder> { ) -> ServiceResult<impl Responder> {
let key = payload.key.clone();
let res = data.captcha.verify_pow(payload.into_inner()).await?; let res = data.captcha.verify_pow(payload.into_inner()).await?;
record_solve(&key, &data.db).await;
let payload = ValidationToken { token: res }; let payload = ValidationToken { token: res };
Ok(HttpResponse::Ok().json(payload)) Ok(HttpResponse::Ok().json(payload))
} }

View File

@@ -14,11 +14,13 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
//! PoW success token module
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use m_captcha::cache::messages::VerifyCaptchaResult; use m_captcha::cache::messages::VerifyCaptchaResult;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::record_confirm;
use crate::errors::*; use crate::errors::*;
use crate::Data; use crate::Data;
@@ -29,16 +31,19 @@ pub struct CaptchaValidateResp {
// API keys are mcaptcha actor names // API keys are mcaptcha actor names
/// route hander that validates a PoW solution token
pub async fn validate_captcha_token( pub async fn validate_captcha_token(
payload: web::Json<VerifyCaptchaResult>, payload: web::Json<VerifyCaptchaResult>,
data: web::Data<Data>, data: web::Data<Data>,
) -> ServiceResult<impl Responder> { ) -> ServiceResult<impl Responder> {
let key = payload.key.clone();
let res = data let res = data
.captcha .captcha
.validate_verification_tokens(payload.into_inner()) .validate_verification_tokens(payload.into_inner())
.await?; .await?;
let payload = CaptchaValidateResp { valid: res }; let payload = CaptchaValidateResp { valid: res };
println!("{:?}", &payload); record_confirm(&key, &data.db).await;
//println!("{:?}", &payload);
Ok(HttpResponse::Ok().json(payload)) Ok(HttpResponse::Ok().json(payload))
} }