diff --git a/src/cache/mod.rs b/src/cache/mod.rs
index 710c67c..92612cf 100644
--- a/src/cache/mod.rs
+++ b/src/cache/mod.rs
@@ -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,
}
diff --git a/src/cache/redis.rs b/src/cache/redis.rs
index ae40835..5273550 100644
--- a/src/cache/redis.rs
+++ b/src/cache/redis.rs
@@ -16,16 +16,18 @@
* along with this program. If not, see .
*/
//! 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 {
+ 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
diff --git a/src/master/redis/master.rs b/src/master/redis/master.rs
index 9d1df46..7de8f41 100644
--- a/src/master/redis/master.rs
+++ b/src/master/redis/master.rs
@@ -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 {
diff --git a/src/master/redis/mod.rs b/src/master/redis/mod.rs
index fbed376..09f3c9a 100644
--- a/src/master/redis/mod.rs
+++ b/src/master/redis/mod.rs
@@ -16,5 +16,4 @@
* along with this program. If not, see .
*/
-pub mod connection;
pub mod master;
diff --git a/src/master/redis/connection.rs b/src/redis/mcaptcha_redis.rs
similarity index 74%
rename from src/master/redis/connection.rs
rename to src/redis/mcaptcha_redis.rs
index ab57d55..d6f5f99 100644
--- a/src/master/redis/connection.rs
+++ b/src/redis/mcaptcha_redis.rs
@@ -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 {
+ 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 {
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());
}
}
diff --git a/src/redis.rs b/src/redis/mod.rs
similarity index 99%
rename from src/redis.rs
rename to src/redis/mod.rs
index 7f3e971..4f0bee3 100644
--- a/src/redis.rs
+++ b/src/redis/mod.rs
@@ -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