1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use actix_identity::Identity;
use actix_web::{web, HttpResponse, Responder};
use libmcaptcha::defense::Level;
use serde::{Deserialize, Serialize};
use db_core::errors::DBError;
use db_core::CreateCaptcha as DBCreateCaptcha;
use super::get_random;
use crate::errors::*;
use crate::AppData;
#[derive(Serialize, Deserialize)]
pub struct CreateCaptcha {
pub levels: Vec<Level>,
pub duration: u32,
pub description: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MCaptchaDetails {
pub name: String,
pub key: String,
}
#[my_codegen::post(
path = "crate::V1_API_ROUTES.captcha.create",
wrap = "crate::api::v1::get_middleware()"
)]
pub async fn create(
payload: web::Json<CreateCaptcha>,
data: AppData,
id: Identity,
) -> ServiceResult<impl Responder> {
let username = id.identity().unwrap();
let mcaptcha_config = runner::create(&payload, &data, &username).await?;
Ok(HttpResponse::Ok().json(mcaptcha_config))
}
pub mod runner {
use super::*;
use libmcaptcha::DefenseBuilder;
pub async fn create(
payload: &CreateCaptcha,
data: &AppData,
username: &str,
) -> ServiceResult<MCaptchaDetails> {
let mut defense = DefenseBuilder::default();
for level in payload.levels.iter() {
defense.add_level(*level)?;
}
defense.build()?;
let mut key;
let duration = payload.duration as i32;
loop {
key = get_random(32);
let p = DBCreateCaptcha {
description: &payload.description,
key: &key,
duration,
};
match data.db.create_captcha(username, &p).await {
Ok(_) => break,
Err(DBError::SecretTaken) => continue,
Err(e) => return Err(e.into()),
}
}
data.db
.add_captcha_levels(username, &key, &payload.levels)
.await?;
let mcaptcha_config = MCaptchaDetails {
name: payload.description.clone(),
key,
};
Ok(mcaptcha_config)
}
}