encryption-rust 1.3.0

可插拔密码学组件库的 Rust 实现:在统一契约下提供对称加密、非对称加密、哈希、密钥派生(HKDF / PBKDF2 / Argon2 / scrypt)、签名(SM2 / ECDSA / Ed25519)、密钥协商(ECDH / X25519)与后量子密钥封装(ML-KEM),包含 AES/Sodium 与国密 SM2/SM3/SM4/ZUC 等实现
Documentation
// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz

//! warp 0.4 集成。
//!
//! warp 没有提取器 trait,也没有 `with_state` —— 它靠**闭包捕获**把一个
//! `Clone` 的值接进过滤器链。所以这里没有 `impl`,只有一个组合子:
//!
//! ```no_run
//! # fn main() {
//! use encryption::guard::Guard;
//! use encryption::integrations::warp::with_guard;
//! use warp::Filter;
//!
//! let guard: Guard = todo!();
//! let route = warp::path("encrypt")
//!     .and(with_guard(guard))
//!     .map(|guard: Guard| guard.encrypt("13800138000".as_bytes()).unwrap().len());
//! # let _ = route;
//! # }
//! ```
//!
//! 这与 warp 文档里 `warp::any().map(move || state.clone())` 的写法是同一件事,
//! 只是把「克隆共享状态」这一步收进了一个有名字的组合子,免得每个项目各写一遍。

use std::convert::Infallible;

use warp::Filter;

use crate::guard::Guard;

/// 造一个产出 [`Guard`] 的过滤器,供 `.and(...)` 接进路由链。
///
/// 每次请求克隆一次 `Arc`(引用计数递增),不含任何密钥拷贝。
pub fn with_guard(guard: Guard) -> impl Filter<Extract = (Guard,), Error = Infallible> + Clone {
    warp::any().map(move || guard.clone())
}

#[cfg(test)]
mod tests {
    use super::*;
    use warp::Filter;

    fn guard() -> Guard {
        Guard::from_master_key(&[7u8; 32], "aes-256-gcm").unwrap()
    }

    #[tokio::test]
    async fn filter_yields_the_guard() {
        let route = warp::any()
            .and(with_guard(guard()))
            .map(|g: Guard| g.identifiers().len().to_string());

        let value = warp::test::request().filter(&route).await.unwrap();
        assert_eq!(value, "5");
    }

    /// 同一把守卫进到处理器里,密文互通。
    #[tokio::test]
    async fn handler_and_state_share_one_encrypter() {
        let state = guard();
        let token = state.encrypt("共享".as_bytes()).unwrap();

        let route = warp::any().and(with_guard(guard())).map(move |g: Guard| {
            g.decrypt(&token)
                .map(|plain| String::from_utf8_lossy(&plain).into_owned())
                .unwrap_or_else(|_| "解不开".into())
        });

        let value = warp::test::request().filter(&route).await.unwrap();
        assert_eq!(value, "共享");
    }

    /// 过滤器必须 `Clone` —— warp 的每个组合子都要求这一点。
    #[tokio::test]
    async fn filter_is_cloneable_and_reusable() {
        let filter = with_guard(guard());
        let a = filter.clone();
        let b = filter;

        let route_a = warp::any().and(a).map(|g: Guard| g.identifiers().len());
        let route_b = warp::any().and(b).map(|g: Guard| g.identifiers().len());

        assert_eq!(warp::test::request().filter(&route_a).await.unwrap(), 5);
        assert_eq!(warp::test::request().filter(&route_b).await.unwrap(), 5);
    }
}