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")]
|
#[cfg(feature = "full")]
|
||||||
pub mod hashcache;
|
pub mod hashcache;
|
||||||
|
//#[cfg(feature = "full")]
|
||||||
|
//pub mod redis;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct AddChallenge {
|
pub struct AddChallenge {
|
||||||
pub difficulty: usize,
|
pub difficulty: u32,
|
||||||
pub duration: u64,
|
pub duration: u64,
|
||||||
pub challenge: String,
|
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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
//! Cache implementation that uses Redis
|
//! Cache implementation that uses Redis
|
||||||
use crate::redis::Redis;
|
use crate::redis::mcaptcha_redis::MCaptchaRedis;
|
||||||
|
use crate::redis::RedisConfig;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use super::messages::*;
|
use super::messages::*;
|
||||||
|
use super::AddChallenge;
|
||||||
use super::Save;
|
use super::Save;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
pub struct RedisCache(Redis);
|
pub struct RedisCache(MCaptchaRedis);
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
/// cache datastructure implementing [Save]
|
/// cache datastructure implementing [Save]
|
||||||
|
@ -35,15 +37,26 @@ pub struct HashCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedisCache {
|
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
|
// save [PoWConfig] to cache
|
||||||
async fn save_pow_config(&mut self, config: CachePoW) -> CaptchaResult<()> {
|
async fn save_pow_config(&mut self, config: CachePoW) -> CaptchaResult<()> {
|
||||||
let challenge = config.string;
|
let challenge = config.string;
|
||||||
let config: CachedPoWConfig = CachedPoWConfig {
|
let payload: AddChallenge = AddChallenge {
|
||||||
key: config.key,
|
challenge: config.string,
|
||||||
difficulty_factor: config.difficulty_factor,
|
difficulty: config.difficulty_factor as usize,
|
||||||
duration: config.duration,
|
duration: config.duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let payload = serde_json::to_string(&payload).unwrap();
|
||||||
|
|
||||||
// {MCAPTCHA_NAME}:difficulty_map:challenge (difficulty_factor -> duration) EX duration
|
// {MCAPTCHA_NAME}:difficulty_map:challenge (difficulty_factor -> duration) EX duration
|
||||||
|
|
||||||
// TODO use hashmap
|
// TODO use hashmap
|
||||||
|
|
|
@ -19,10 +19,10 @@ use std::sync::mpsc;
|
||||||
|
|
||||||
use actix::dev::*;
|
use actix::dev::*;
|
||||||
|
|
||||||
use super::connection::MCaptchaRedis;
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::master::messages::{AddSite, AddVisitor};
|
use crate::master::messages::{AddSite, AddVisitor};
|
||||||
use crate::master::Master as MasterTrait;
|
use crate::master::Master as MasterTrait;
|
||||||
|
use crate::redis::mcaptcha_redis::MCaptchaRedis;
|
||||||
use crate::redis::RedisConfig;
|
use crate::redis::RedisConfig;
|
||||||
|
|
||||||
pub struct Master {
|
pub struct Master {
|
||||||
|
|
|
@ -16,5 +16,4 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod connection;
|
|
||||||
pub mod master;
|
pub mod master;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
*/
|
*/
|
||||||
use redis::Value;
|
use redis::Value;
|
||||||
|
|
||||||
|
use crate::cache::messages::VerifyCaptchaResult;
|
||||||
|
use crate::cache::AddChallenge;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::master::messages::{AddSite, AddVisitor};
|
use crate::master::messages::{AddSite, AddVisitor};
|
||||||
use crate::master::AddVisitorResult;
|
use crate::master::AddVisitorResult;
|
||||||
|
@ -36,6 +38,8 @@ const ADD_VISITOR: &str = "MCAPTCHA_CACHE.ADD_VISITOR";
|
||||||
const DEL: &str = "MCAPTCHA_CACHE.DELETE_CAPTCHA";
|
const DEL: &str = "MCAPTCHA_CACHE.DELETE_CAPTCHA";
|
||||||
const ADD_CAPTCHA: &str = "MCAPTCHA_CACHE.ADD_CAPTCHA";
|
const ADD_CAPTCHA: &str = "MCAPTCHA_CACHE.ADD_CAPTCHA";
|
||||||
const CAPTCHA_EXISTS: &str = "MCAPTCHA_CACHE.CAPTCHA_EXISTS";
|
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";
|
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() {
|
for cmd in commands.iter() {
|
||||||
if let Value::Bulk(mut val) = self
|
if let Value::Bulk(mut val) = self
|
||||||
|
@ -138,6 +150,31 @@ impl MCaptchaRedisConnection {
|
||||||
Ok(())
|
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
|
/// Get number of visitors of an mCaptcha object from Redis
|
||||||
pub async fn get_visitors(&self, captcha: &str) -> CaptchaResult<usize> {
|
pub async fn get_visitors(&self, captcha: &str) -> CaptchaResult<usize> {
|
||||||
let visitors: usize = self.0.exec(redis::cmd(GET).arg(&[captcha])).await?;
|
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 CAPTCHA_NAME: &str = "REDIS_CAPTCHA_TEST";
|
||||||
const REDIS_URL: &str = "redis://127.0.1.1/";
|
const REDIS_URL: &str = "redis://127.0.1.1/";
|
||||||
|
const CHALLENGE: &str = "randomchallengestring";
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn redis_master_works() {
|
async fn redis_master_works() {
|
||||||
|
@ -165,11 +203,15 @@ pub mod tests {
|
||||||
{
|
{
|
||||||
let _ = r.delete_captcha(CAPTCHA_NAME).await;
|
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.is_module_loaded().await.is_ok());
|
||||||
assert!(!r.check_captcha_exists(CAPTCHA_NAME).await.unwrap());
|
assert!(!r.check_captcha_exists(CAPTCHA_NAME).await.unwrap());
|
||||||
let add_mcaptcha_msg = AddSite {
|
let add_mcaptcha_msg = AddSite {
|
||||||
id: CAPTCHA_NAME.into(),
|
id: CAPTCHA_NAME.into(),
|
||||||
mcaptcha: get_mcaptcha(),
|
mcaptcha,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(r.add_mcaptcha(add_mcaptcha_msg).await.is_ok());
|
assert!(r.add_mcaptcha(add_mcaptcha_msg).await.is_ok());
|
||||||
|
@ -181,10 +223,32 @@ pub mod tests {
|
||||||
assert_eq!(visitors, 1);
|
assert_eq!(visitors, 1);
|
||||||
|
|
||||||
let add_visitor_msg = AddVisitor(CAPTCHA_NAME.into());
|
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();
|
let visitors = r.get_visitors(CAPTCHA_NAME).await.unwrap();
|
||||||
assert_eq!(visitors, 2);
|
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());
|
assert!(r.delete_captcha(CAPTCHA_NAME).await.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ use redis::Client;
|
||||||
use redis::FromRedisValue;
|
use redis::FromRedisValue;
|
||||||
use redis::{aio::Connection, cluster::ClusterConnection};
|
use redis::{aio::Connection, cluster::ClusterConnection};
|
||||||
|
|
||||||
|
pub mod mcaptcha_redis;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
/// Client configuration
|
/// Client configuration
|
Loading…
Reference in a new issue