encryption/integrations/
salvo.rs1use salvo::extract::Metadata;
33use salvo::http::StatusCode;
34use salvo::prelude::{Depot, Request, Response, Text};
35use salvo::writing::Writer;
36use salvo::{Extractible, async_trait};
37
38use super::GuardNotConfigured;
39use crate::guard::Guard;
40
41#[async_trait]
43impl Writer for GuardNotConfigured {
44 async fn write(self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
45 res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
46 res.render(Text::Plain(self.to_string()));
47 }
48}
49
50#[allow(refining_impl_trait)]
53impl<'ex> Extractible<'ex> for Guard {
54 fn metadata() -> &'static Metadata {
55 static METADATA: Metadata = Metadata::new("Guard");
57 &METADATA
58 }
59
60 async fn extract(
61 _req: &'ex mut Request,
62 depot: &'ex mut Depot,
63 ) -> Result<Self, GuardNotConfigured> {
64 depot
65 .get_typed::<Guard>()
66 .cloned()
67 .map_err(|_| GuardNotConfigured)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 fn guard() -> Guard {
76 Guard::from_master_key(&[7u8; 32], "aes-256-gcm").unwrap()
77 }
78
79 #[test]
80 fn extracts_from_depot() {
81 let mut depot = Depot::new();
82 depot.insert_typed(guard());
83
84 let mut req = Request::new();
85 let extracted = futures_lite_block_on(Guard::extract(&mut req, &mut depot)).unwrap();
86 assert_eq!(extracted.identifiers().len(), 5);
87 }
88
89 #[test]
91 fn missing_depot_entry_is_an_error() {
92 let mut depot = Depot::new();
93 let mut req = Request::new();
94 let err = futures_lite_block_on(Guard::extract(&mut req, &mut depot)).unwrap_err();
95 assert_eq!(err, GuardNotConfigured);
96 }
97
98 #[test]
99 fn handler_and_state_share_one_encrypter() {
100 let state = guard();
101 let token = state.encrypt("共享".as_bytes()).unwrap();
102
103 let mut depot = Depot::new();
104 depot.insert_typed(state);
105
106 let mut req = Request::new();
107 let extracted = futures_lite_block_on(Guard::extract(&mut req, &mut depot)).unwrap();
108 assert_eq!(extracted.decrypt(&token).unwrap(), "共享".as_bytes());
109 }
110
111 fn futures_lite_block_on<F: std::future::Future>(fut: F) -> F::Output {
114 use std::task::{Context, Poll, Waker};
115
116 let mut fut = std::pin::pin!(fut);
117 let waker = Waker::noop();
118 let mut cx = Context::from_waker(waker);
119
120 loop {
121 match fut.as_mut().poll(&mut cx) {
122 Poll::Ready(out) => return out,
123 Poll::Pending => std::thread::yield_now(),
124 }
125 }
126 }
127}