Skip to main content

encryption/integrations/
warp.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! warp 0.4 集成。
4//!
5//! warp 没有提取器 trait,也没有 `with_state` —— 它靠**闭包捕获**把一个
6//! `Clone` 的值接进过滤器链。所以这里没有 `impl`,只有一个组合子:
7//!
8//! ```no_run
9//! # fn main() {
10//! use encryption::guard::Guard;
11//! use encryption::integrations::warp::with_guard;
12//! use warp::Filter;
13//!
14//! let guard: Guard = todo!();
15//! let route = warp::path("encrypt")
16//!     .and(with_guard(guard))
17//!     .map(|guard: Guard| guard.encrypt("13800138000".as_bytes()).unwrap().len());
18//! # let _ = route;
19//! # }
20//! ```
21//!
22//! 这与 warp 文档里 `warp::any().map(move || state.clone())` 的写法是同一件事,
23//! 只是把「克隆共享状态」这一步收进了一个有名字的组合子,免得每个项目各写一遍。
24
25use std::convert::Infallible;
26
27use warp::Filter;
28
29use crate::guard::Guard;
30
31/// 造一个产出 [`Guard`] 的过滤器,供 `.and(...)` 接进路由链。
32///
33/// 每次请求克隆一次 `Arc`(引用计数递增),不含任何密钥拷贝。
34pub fn with_guard(guard: Guard) -> impl Filter<Extract = (Guard,), Error = Infallible> + Clone {
35    warp::any().map(move || guard.clone())
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use warp::Filter;
42
43    fn guard() -> Guard {
44        Guard::from_master_key(&[7u8; 32], "aes-256-gcm").unwrap()
45    }
46
47    #[tokio::test]
48    async fn filter_yields_the_guard() {
49        let route = warp::any()
50            .and(with_guard(guard()))
51            .map(|g: Guard| g.identifiers().len().to_string());
52
53        let value = warp::test::request().filter(&route).await.unwrap();
54        assert_eq!(value, "5");
55    }
56
57    /// 同一把守卫进到处理器里,密文互通。
58    #[tokio::test]
59    async fn handler_and_state_share_one_encrypter() {
60        let state = guard();
61        let token = state.encrypt("共享".as_bytes()).unwrap();
62
63        let route = warp::any().and(with_guard(guard())).map(move |g: Guard| {
64            g.decrypt(&token)
65                .map(|plain| String::from_utf8_lossy(&plain).into_owned())
66                .unwrap_or_else(|_| "解不开".into())
67        });
68
69        let value = warp::test::request().filter(&route).await.unwrap();
70        assert_eq!(value, "共享");
71    }
72
73    /// 过滤器必须 `Clone` —— warp 的每个组合子都要求这一点。
74    #[tokio::test]
75    async fn filter_is_cloneable_and_reusable() {
76        let filter = with_guard(guard());
77        let a = filter.clone();
78        let b = filter;
79
80        let route_a = warp::any().and(a).map(|g: Guard| g.identifiers().len());
81        let route_b = warp::any().and(b).map(|g: Guard| g.identifiers().len());
82
83        assert_eq!(warp::test::request().filter(&route_a).await.unwrap(), 5);
84        assert_eq!(warp::test::request().filter(&route_b).await.unwrap(), 5);
85    }
86}