feat: New SimpleGenerator
to generate the captcha
Signed-off-by: Awiteb <a@4rs.nl>
This commit is contained in:
parent
28425d939f
commit
c6956ad729
3 changed files with 134 additions and 40 deletions
|
@ -1,40 +0,0 @@
|
||||||
// Copyright (c) 2024, Awiteb <a@4rs.nl>
|
|
||||||
// A captcha middleware for Salvo framework.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
use crate::{CaptchaDifficulty, CaptchaName, CaptchaStorage};
|
|
||||||
|
|
||||||
/// Captcha generator, used to generate a new captcha image. This trait are implemented for all [`CaptchaStorage`].
|
|
||||||
pub trait CaptchaGenerator: CaptchaStorage {
|
|
||||||
/// Create a new captcha image and return the token and the image encoded as png. Will return None if the captcha crate failed to create the captcha.
|
|
||||||
///
|
|
||||||
/// The returned captcha image is 220x110 pixels.
|
|
||||||
///
|
|
||||||
/// For more information about the captcha name and difficulty, see the [`README.md`](https://git.4rs.nl/awiteb/salvo-captcha/#captcha-name-and-difficulty).
|
|
||||||
fn new_captcha(
|
|
||||||
&self,
|
|
||||||
name: CaptchaName,
|
|
||||||
difficulty: CaptchaDifficulty,
|
|
||||||
) -> impl std::future::Future<Output = Result<Option<(String, Vec<u8>)>, Self::Error>> + Send
|
|
||||||
{
|
|
||||||
async {
|
|
||||||
let Some((captcha_answer, captcha_image)) =
|
|
||||||
captcha::by_name(difficulty, name).as_tuple()
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let token = self.store_answer(captcha_answer).await?;
|
|
||||||
Ok(Some((token, captcha_image)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> CaptchaGenerator for T where T: CaptchaStorage {}
|
|
27
src/captcha_gen/mod.rs
Normal file
27
src/captcha_gen/mod.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (c) 2024, Awiteb <a@4rs.nl>
|
||||||
|
// A captcha middleware for Salvo framework.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#[cfg(feature = "simple_generator")]
|
||||||
|
mod simple_generator;
|
||||||
|
|
||||||
|
#[cfg(feature = "simple_generator")]
|
||||||
|
pub use simple_generator::*;
|
||||||
|
|
||||||
|
/// Captcha generator, used to generate a new captcha image and answer.
|
||||||
|
pub trait CaptchaGenerator: Send {
|
||||||
|
/// The error type of the captcha generator
|
||||||
|
type Error: std::error::Error;
|
||||||
|
|
||||||
|
/// Create a new captcha image and return the answer and the image encoded as png
|
||||||
|
fn new_captcha(
|
||||||
|
&self,
|
||||||
|
) -> impl std::future::Future<Output = Result<(String, Vec<u8>), Self::Error>> + Send;
|
||||||
|
}
|
107
src/captcha_gen/simple_generator.rs
Normal file
107
src/captcha_gen/simple_generator.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright (c) 2024, Awiteb <a@4rs.nl>
|
||||||
|
// A captcha middleware for Salvo framework.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
use crate::CaptchaGenerator;
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
/// Supported captcha names
|
||||||
|
///
|
||||||
|
/// See [`README.md`](https://git.4rs.nl/awiteb/salvo-captcha/#captcha-name-and-difficulty) for more information.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum CaptchaName {
|
||||||
|
/// Plain text, without any distortion
|
||||||
|
Normal,
|
||||||
|
/// Slightly twisted text
|
||||||
|
SlightlyTwisted,
|
||||||
|
/// Very twisted text
|
||||||
|
VeryTwisted,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supported captcha difficulties
|
||||||
|
///
|
||||||
|
/// See [`README.md`](https://git.4rs.nl/awiteb/salvo-captcha/#captcha-name-and-difficulty) for more information.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum CaptchaDifficulty {
|
||||||
|
/// Easy to read text
|
||||||
|
Easy,
|
||||||
|
/// Medium difficulty text
|
||||||
|
Medium,
|
||||||
|
/// Hard to read text
|
||||||
|
Hard,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CaptchaName> for captcha::CaptchaName {
|
||||||
|
/// Function to convert the [`CaptchaName`] to the [`captcha::CaptchaName`]
|
||||||
|
fn from(value: CaptchaName) -> Self {
|
||||||
|
match value {
|
||||||
|
CaptchaName::Normal => Self::Lucy,
|
||||||
|
CaptchaName::SlightlyTwisted => Self::Amelia,
|
||||||
|
CaptchaName::VeryTwisted => Self::Mila,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CaptchaDifficulty> for captcha::Difficulty {
|
||||||
|
/// Function to convert the [`CaptchaDifficulty`] to the [`captcha::Difficulty`]
|
||||||
|
fn from(value: CaptchaDifficulty) -> captcha::Difficulty {
|
||||||
|
match value {
|
||||||
|
CaptchaDifficulty::Easy => Self::Easy,
|
||||||
|
CaptchaDifficulty::Medium => Self::Medium,
|
||||||
|
CaptchaDifficulty::Hard => Self::Hard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Error type for the [`SimpleGenerator`]
|
||||||
|
pub enum SimpleGeneratorError {
|
||||||
|
/// Failed to encode the captcha to png image
|
||||||
|
FaildEncodedToPng,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SimpleGeneratorError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Faild to encode the captcha to png image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for SimpleGeneratorError {}
|
||||||
|
|
||||||
|
/// The simple captcha generator
|
||||||
|
pub struct SimpleGenerator {
|
||||||
|
name: CaptchaName,
|
||||||
|
difficulty: CaptchaDifficulty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleGenerator {
|
||||||
|
/// Create new [`SimpleGenerator`] instance
|
||||||
|
pub const fn new(name: CaptchaName, difficulty: CaptchaDifficulty) -> Self {
|
||||||
|
Self { name, difficulty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CaptchaGenerator for SimpleGenerator {
|
||||||
|
type Error = SimpleGeneratorError;
|
||||||
|
|
||||||
|
/// The returned captcha image is 220x110 pixels in png format.
|
||||||
|
///
|
||||||
|
/// For more information about the captcha name and difficulty, see the [`README.md`](https://git.4rs.nl/awiteb/salvo-captcha/#captcha-name-and-difficulty).
|
||||||
|
async fn new_captcha(&self) -> Result<(String, Vec<u8>), Self::Error> {
|
||||||
|
let Some((captcha_answer, captcha_image)) =
|
||||||
|
captcha::by_name(self.difficulty.into(), self.name.into()).as_tuple()
|
||||||
|
else {
|
||||||
|
return Err(SimpleGeneratorError::FaildEncodedToPng);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((captcha_answer, captcha_image))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue