redis: add and get challenge
This commit is contained in:
parent
0ff9cf9cb0
commit
a98658c57d
6 changed files with 90 additions and 11 deletions
4
src/cache/mod.rs
vendored
4
src/cache/mod.rs
vendored
|
@ -21,10 +21,12 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
#[cfg(feature = "full")]
|
||||
pub mod hashcache;
|
||||
//#[cfg(feature = "full")]
|
||||
//pub mod redis;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AddChallenge {
|
||||
pub difficulty: usize,
|
||||
pub difficulty: u32,
|
||||
pub duration: u64,
|
||||
pub challenge: String,
|
||||
}
|
||||
|
|
23
src/cache/redis.rs
vendored
23
src/cache/redis.rs
vendored
|
@ -16,16 +16,18 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! Cache implementation that uses Redis
|
||||
use crate::redis::Redis;
|
||||
use crate::redis::mcaptcha_redis::MCaptchaRedis;
|
||||
use crate::redis::RedisConfig;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix::prelude::*;
|
||||
|
||||
use super::messages::*;
|
||||
use super::AddChallenge;
|
||||
use super::Save;
|
||||
use crate::errors::*;
|
||||
|
||||
pub struct RedisCache(Redis);
|
||||
pub struct RedisCache(MCaptchaRedis);
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
/// cache datastructure implementing [Save]
|
||||
|
@ -35,15 +37,26 @@ pub struct HashCache {
|
|||
}
|
||||
|
||||
impl RedisCache {
|
||||
/// Get new [MCaptchaRedis]. Use this when executing commands that are
|
||||
/// only supported by mCaptcha Redis module. Internally, when object
|
||||
/// is created, checks are performed to check if the module is loaded and if
|
||||
/// the required commands are available
|
||||
pub async fn new(redis: RedisConfig) -> CaptchaResult<Self> {
|
||||
let m = MCaptchaRedis::new(redis).await?;
|
||||
Ok(Self(m))
|
||||
}
|
||||
|
||||
// save [PoWConfig] to cache
|
||||
async fn save_pow_config(&mut self, config: CachePoW) -> CaptchaResult<()> {
|
||||
let challenge = config.string;
|
||||
let config: CachedPoWConfig = CachedPoWConfig {
|
||||
key: config.key,
|
||||
difficulty_factor: config.difficulty_factor,
|
||||
let payload: AddChallenge = AddChallenge {
|
||||
challenge: config.string,
|
||||
difficulty: config.difficulty_factor as usize,
|
||||
duration: config.duration,
|
||||
};
|
||||
|
||||
let payload = serde_json::to_string(&payload).unwrap();
|
||||
|
||||
// {MCAPTCHA_NAME}:difficulty_map:challenge (difficulty_factor -> duration) EX duration
|
||||
|
||||
// TODO use hashmap
|
||||
|
|
|
@ -19,10 +19,10 @@ use std::sync::mpsc;
|
|||
|
||||
use actix::dev::*;
|
||||
|
||||
use super::connection::MCaptchaRedis;
|
||||
use crate::errors::*;
|
||||
use crate::master::messages::{AddSite, AddVisitor};
|
||||
use crate::master::Master as MasterTrait;
|
||||
use crate::redis::mcaptcha_redis::MCaptchaRedis;
|
||||
use crate::redis::RedisConfig;
|
||||
|
||||
pub struct Master {
|
||||
|
|
|
@ -16,5 +16,4 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pub mod connection;
|
||||
pub mod master;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
*/
|
||||
use redis::Value;
|
||||
|
||||
use crate::cache::messages::VerifyCaptchaResult;
|
||||
use crate::cache::AddChallenge;
|
||||
use crate::errors::*;
|
||||
use crate::master::messages::{AddSite, AddVisitor};
|
||||
use crate::master::AddVisitorResult;
|
||||
|
@ -36,6 +38,8 @@ const ADD_VISITOR: &str = "MCAPTCHA_CACHE.ADD_VISITOR";
|
|||
const DEL: &str = "MCAPTCHA_CACHE.DELETE_CAPTCHA";
|
||||
const ADD_CAPTCHA: &str = "MCAPTCHA_CACHE.ADD_CAPTCHA";
|
||||
const CAPTCHA_EXISTS: &str = "MCAPTCHA_CACHE.CAPTCHA_EXISTS";
|
||||
const ADD_CHALLENGE: &str = "MCAPTCHA_CACHE.ADD_CHALLENGE";
|
||||
const GET_CHALLENGE: &str = "MCAPTCHA_CACHE.GET_CHALLENGE";
|
||||
|
||||
const MODULE_NAME: &str = "mcaptcha_cahce";
|
||||
|
||||
|
@ -74,7 +78,15 @@ impl MCaptchaRedisConnection {
|
|||
}
|
||||
}
|
||||
|
||||
let commands = vec![ADD_VISITOR, ADD_CAPTCHA, DEL, CAPTCHA_EXISTS, GET];
|
||||
let commands = vec![
|
||||
ADD_VISITOR,
|
||||
ADD_CAPTCHA,
|
||||
DEL,
|
||||
CAPTCHA_EXISTS,
|
||||
GET,
|
||||
ADD_CHALLENGE,
|
||||
GET_CHALLENGE,
|
||||
];
|
||||
|
||||
for cmd in commands.iter() {
|
||||
if let Value::Bulk(mut val) = self
|
||||
|
@ -138,6 +150,31 @@ impl MCaptchaRedisConnection {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete an mCaptcha object from Redis
|
||||
pub async fn add_challenge(
|
||||
&self,
|
||||
captcha: &str,
|
||||
challlenge: &AddChallenge,
|
||||
) -> CaptchaResult<()> {
|
||||
let payload = serde_json::to_string(challlenge).unwrap();
|
||||
self.0
|
||||
.exec(redis::cmd(ADD_CHALLENGE).arg(&[captcha, &payload]))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete an mCaptcha object from Redis
|
||||
pub async fn get_challenge(
|
||||
&self,
|
||||
msg: &VerifyCaptchaResult,
|
||||
) -> CaptchaResult<AddVisitorResult> {
|
||||
let challege: String = self
|
||||
.0
|
||||
.exec(redis::cmd(GET_CHALLENGE).arg(&[&msg.key, &msg.token]))
|
||||
.await?;
|
||||
Ok(serde_json::from_str(&challege).unwrap())
|
||||
}
|
||||
|
||||
/// Get number of visitors of an mCaptcha object from Redis
|
||||
pub async fn get_visitors(&self, captcha: &str) -> CaptchaResult<usize> {
|
||||
let visitors: usize = self.0.exec(redis::cmd(GET).arg(&[captcha])).await?;
|
||||
|
@ -153,6 +190,7 @@ pub mod tests {
|
|||
|
||||
const CAPTCHA_NAME: &str = "REDIS_CAPTCHA_TEST";
|
||||
const REDIS_URL: &str = "redis://127.0.1.1/";
|
||||
const CHALLENGE: &str = "randomchallengestring";
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn redis_master_works() {
|
||||
|
@ -165,11 +203,15 @@ pub mod tests {
|
|||
{
|
||||
let _ = r.delete_captcha(CAPTCHA_NAME).await;
|
||||
}
|
||||
|
||||
let mcaptcha = get_mcaptcha();
|
||||
// let duration = mcaptcha.get_duration();
|
||||
|
||||
assert!(r.is_module_loaded().await.is_ok());
|
||||
assert!(!r.check_captcha_exists(CAPTCHA_NAME).await.unwrap());
|
||||
let add_mcaptcha_msg = AddSite {
|
||||
id: CAPTCHA_NAME.into(),
|
||||
mcaptcha: get_mcaptcha(),
|
||||
mcaptcha,
|
||||
};
|
||||
|
||||
assert!(r.add_mcaptcha(add_mcaptcha_msg).await.is_ok());
|
||||
|
@ -181,10 +223,32 @@ pub mod tests {
|
|||
assert_eq!(visitors, 1);
|
||||
|
||||
let add_visitor_msg = AddVisitor(CAPTCHA_NAME.into());
|
||||
assert!(r.add_visitor(add_visitor_msg).await.is_ok());
|
||||
let resp = r.add_visitor(add_visitor_msg.clone()).await;
|
||||
assert!(resp.is_ok());
|
||||
assert!(resp.unwrap().is_some());
|
||||
let visitors = r.get_visitors(CAPTCHA_NAME).await.unwrap();
|
||||
assert_eq!(visitors, 2);
|
||||
|
||||
let add_visitor_res = r.add_visitor(add_visitor_msg).await.unwrap().unwrap();
|
||||
let add_challenge_msg = AddChallenge {
|
||||
difficulty: add_visitor_res.difficulty_factor,
|
||||
duration: add_visitor_res.duration,
|
||||
challenge: CHALLENGE.into(),
|
||||
};
|
||||
|
||||
assert!(r
|
||||
.add_challenge(CAPTCHA_NAME, &add_challenge_msg)
|
||||
.await
|
||||
.is_ok());
|
||||
|
||||
let verify_msg = VerifyCaptchaResult {
|
||||
token: CHALLENGE.into(),
|
||||
key: CAPTCHA_NAME.into(),
|
||||
};
|
||||
let x = r.get_challenge(&verify_msg).await.unwrap();
|
||||
assert_eq!(x.duration, add_challenge_msg.duration);
|
||||
assert_eq!(x.difficulty_factor, add_challenge_msg.difficulty);
|
||||
|
||||
assert!(r.delete_captcha(CAPTCHA_NAME).await.is_ok());
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ use redis::Client;
|
|||
use redis::FromRedisValue;
|
||||
use redis::{aio::Connection, cluster::ClusterConnection};
|
||||
|
||||
pub mod mcaptcha_redis;
|
||||
use crate::errors::*;
|
||||
|
||||
/// Client configuration
|
Loading…
Reference in a new issue