redis: add and get challenge

This commit is contained in:
Aravinth Manivannan 2021-06-09 21:00:29 +05:30
parent 0ff9cf9cb0
commit a98658c57d
Signed by: realaravinth
GPG Key ID: AD9F0F08E855ED88
6 changed files with 90 additions and 11 deletions

4
src/cache/mod.rs vendored
View File

@ -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
View File

@ -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

View File

@ -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 {

View File

@ -16,5 +16,4 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pub mod connection;
pub mod master;

View File

@ -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());
}
}

View File

@ -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