Compare commits
5 commits
4ce55e73f0
...
f2952ce449
Author | SHA1 | Date | |
---|---|---|---|
f2952ce449 | |||
7f6d16c046 | |||
4767916166 | |||
ebed69cce9 | |||
0906b818a4 |
9 changed files with 35 additions and 15 deletions
|
@ -18,7 +18,7 @@ jobs:
|
||||||
- name: Build the source code
|
- name: Build the source code
|
||||||
run: cargo build
|
run: cargo build
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: cargo build -F 'cacache-storage' --example simple_login
|
run: cargo build -F 'simple-generator' --example simple_login
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --tests --all-features
|
run: cargo test --tests --all-features
|
||||||
- name: Check the code format
|
- name: Check the code format
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "salvo-captcha"
|
name = "salvo-captcha"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
rust-version = "1.75.0"
|
rust-version = "1.75.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Awiteb <a@4rs.nl>"]
|
authors = ["Awiteb <a@4rs.nl>"]
|
||||||
|
@ -24,7 +24,7 @@ either = { version = "1.13.0", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
cacache-storage = ["dep:cacache"]
|
cacache-storage = ["dep:cacache"]
|
||||||
simple_generator = ["dep:captcha"]
|
simple-generator = ["dep:captcha"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.9"
|
tempfile = "3.9"
|
||||||
|
@ -35,4 +35,4 @@ rstest = "0.22.0"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "simple_login"
|
name = "simple_login"
|
||||||
required-features = ["simple_generator"]
|
required-features = ["simple-generator"]
|
||||||
|
|
2
Justfile
2
Justfile
|
@ -19,7 +19,7 @@ _default:
|
||||||
# Run the CI (Local use only)
|
# Run the CI (Local use only)
|
||||||
@ci:
|
@ci:
|
||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
cargo build -F 'simple_generator' --example simple_login
|
cargo build -F 'simple-generator' --example simple_login
|
||||||
cargo clippy --workspace --all-targets --examples --tests --all-features -- -D warnings
|
cargo clippy --workspace --all-targets --examples --tests --all-features -- -D warnings
|
||||||
cargo nextest run --workspace --all-targets --all-features
|
cargo nextest run --workspace --all-targets --all-features
|
||||||
@{{JUST_EXECUTABLE}} msrv
|
@{{JUST_EXECUTABLE}} msrv
|
||||||
|
|
|
@ -46,7 +46,14 @@ We provide fully customizable query parameters, form fields, and headers to find
|
||||||
|
|
||||||
## Captcha Generator
|
## Captcha Generator
|
||||||
|
|
||||||
We provide [`SimpleCaptchaGenerator`] which is a simple captcha generator based on the [`captcha`] crate. You can implement your own captcha generator by implementing the [`CaptchaGenerator`] trait.
|
We provide [`SimpleCaptchaGenerator`] which is a simple captcha generator based on the [`captcha`] crate, you can enable it by enabling the `simple-generator` feature.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
salvo-captcha = { version = "0.2", features = ["simple-generator"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
You can implement your own generator by implementing the [`CaptchaGenerator`] trait.
|
||||||
|
|
||||||
### Captcha name and difficulty
|
### Captcha name and difficulty
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#[cfg(feature = "simple_generator")]
|
#[cfg(feature = "simple-generator")]
|
||||||
mod simple_generator;
|
mod simple_generator;
|
||||||
|
|
||||||
#[cfg(feature = "simple_generator")]
|
#[cfg(feature = "simple-generator")]
|
||||||
pub use simple_generator::*;
|
pub use simple_generator::*;
|
||||||
|
|
||||||
/// Captcha generator, used to generate a new captcha image and answer.
|
/// Captcha generator, used to generate a new captcha image and answer.
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl Display for SimpleGeneratorError {
|
||||||
|
|
||||||
impl std::error::Error for SimpleGeneratorError {}
|
impl std::error::Error for SimpleGeneratorError {}
|
||||||
|
|
||||||
/// The simple captcha generator
|
/// A simple captcha generator, using the [`captcha`](https://crates.io/crates/captcha) crate.
|
||||||
pub struct SimpleGenerator {
|
pub struct SimpleGenerator {
|
||||||
name: CaptchaName,
|
name: CaptchaName,
|
||||||
difficulty: CaptchaDifficulty,
|
difficulty: CaptchaDifficulty,
|
||||||
|
@ -93,8 +93,6 @@ impl CaptchaGenerator for SimpleGenerator {
|
||||||
type Error = SimpleGeneratorError;
|
type Error = SimpleGeneratorError;
|
||||||
|
|
||||||
/// The returned captcha image is 220x110 pixels in png format.
|
/// 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> {
|
async fn new_captcha(&self) -> Result<(String, Vec<u8>), Self::Error> {
|
||||||
let Some((captcha_answer, captcha_image)) =
|
let Some((captcha_answer, captcha_image)) =
|
||||||
captcha::by_name(self.difficulty.into(), self.name.into()).as_tuple()
|
captcha::by_name(self.difficulty.into(), self.name.into()).as_tuple()
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -29,7 +29,21 @@ pub use {captcha_gen::*, finder::*, storage::*};
|
||||||
/// Key used to insert the captcha state into the depot
|
/// Key used to insert the captcha state into the depot
|
||||||
pub const CAPTCHA_STATE_KEY: &str = "::salvo_captcha::captcha_state";
|
pub const CAPTCHA_STATE_KEY: &str = "::salvo_captcha::captcha_state";
|
||||||
|
|
||||||
/// Captcha struct, contains the token and answer.
|
/// The captcha middleware
|
||||||
|
///
|
||||||
|
/// The captcha middleware is used to check the captcha token and answer from
|
||||||
|
/// the request. You can use the [`CaptchaBuilder`] to create a new captcha
|
||||||
|
/// middleware.
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
/// You need to generate the captcha token and answer before, then the captcha
|
||||||
|
/// middleware will check the token and answer from the request using the finder
|
||||||
|
/// and storage you provided. The captcha middleware will insert the
|
||||||
|
/// [`CaptchaState`] into the depot, you can get the captcha state from the
|
||||||
|
/// depot using the [`CaptchaDepotExt::get_captcha_state`] trait, which is
|
||||||
|
/// implemented for the [`Depot`].
|
||||||
|
///
|
||||||
|
/// Check the [`examples`](https://git.4rs.nl/awiteb/salvo-captcha/src/branch/master/examples) for more information.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Captcha<S, F>
|
pub struct Captcha<S, F>
|
||||||
where
|
where
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::{
|
||||||
|
|
||||||
use crate::CaptchaStorage;
|
use crate::CaptchaStorage;
|
||||||
|
|
||||||
/// The [`cacache`] storage.
|
/// The [`cacache`] storage. Store the token and answer in the disk.
|
||||||
///
|
///
|
||||||
/// [`cacache`]: https://github.com/zkat/cacache-rs
|
/// [`cacache`]: https://github.com/zkat/cacache-rs
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -26,7 +26,7 @@ pub struct CacacheStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacacheStorage {
|
impl CacacheStorage {
|
||||||
/// Create a new CacacheStorage
|
/// Create a new [`CacacheStorage`] instance with the cache directory.
|
||||||
pub fn new(cache_dir: impl Into<PathBuf>) -> Self {
|
pub fn new(cache_dir: impl Into<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cache_dir: cache_dir.into(),
|
cache_dir: cache_dir.into(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::CaptchaStorage;
|
use crate::CaptchaStorage;
|
||||||
|
|
||||||
/// Captcha storage implementation using an in-memory HashMap.
|
/// Captcha storage implementation using an in-memory [HashMap].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MemoryStorage(RwLock<HashMap<String, (u64, String)>>);
|
pub struct MemoryStorage(RwLock<HashMap<String, (u64, String)>>);
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ impl MemoryStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CaptchaStorage for MemoryStorage {
|
impl CaptchaStorage for MemoryStorage {
|
||||||
|
/// This storage does not return any error.
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
async fn store_answer(&self, answer: String) -> Result<String, Self::Error> {
|
async fn store_answer(&self, answer: String) -> Result<String, Self::Error> {
|
||||||
|
|
Loading…
Reference in a new issue