use rocket::State;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome, Request};
use super::GuardNotConfigured;
use crate::guard::Guard;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Guard {
type Error = GuardNotConfigured;
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
match request.guard::<&State<Guard>>().await {
Outcome::Success(state) => Outcome::Success(state.inner().clone()),
Outcome::Error(_) | Outcome::Forward(_) => {
Outcome::Error((Status::InternalServerError, GuardNotConfigured))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rocket::local::blocking::Client;
use rocket::{get, routes};
fn guard() -> Guard {
Guard::from_master_key(&[7u8; 32], "aes-256-gcm").unwrap()
}
#[get("/encrypt")]
fn encrypt_route(guard: Guard) -> String {
let blob = guard.encrypt("13800138000".as_bytes()).unwrap();
crate::internal::hex_encode(&blob)
}
#[get("/decrypt/<payload>")]
fn decrypt_route(guard: Guard, payload: &str) -> String {
let blob = crate::internal::hex_decode(payload).unwrap_or_default();
guard
.decrypt(&blob)
.map(|plain| String::from_utf8_lossy(&plain).into_owned())
.unwrap_or_else(|_| "解不开".into())
}
#[test]
fn guard_is_injectable_end_to_end() {
let rocket = rocket::build()
.manage(guard())
.mount("/", routes![encrypt_route, decrypt_route]);
let client = Client::tracked(rocket).expect("rocket 应当能启动");
let res = client.get("/encrypt").dispatch();
assert_eq!(res.status(), Status::Ok);
let cipher = res.into_string().unwrap();
assert!(cipher.len() > 20, "应当拿到一段密文,实际 {cipher:?}");
let res = client.get(format!("/decrypt/{cipher}")).dispatch();
assert_eq!(res.status(), Status::Ok);
assert_eq!(res.into_string().unwrap(), "13800138000");
}
#[test]
fn missing_managed_state_is_a_500() {
let rocket = rocket::build().mount("/", routes![encrypt_route]);
let client = Client::tracked(rocket).expect("rocket 应当能启动");
let res = client.get("/encrypt").dispatch();
assert_eq!(res.status(), Status::InternalServerError);
}
}