aleo_development_server/helpers/
auth.rs1use crate::RestError;
18
19use snarkvm::prelude::{Address, Network};
20
21use anyhow::{anyhow, Result};
22use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
23use once_cell::sync::OnceCell;
24use rand::{thread_rng, Rng};
25use serde::{Deserialize, Serialize};
26use time::OffsetDateTime;
27use warp::{reject, Filter, Rejection};
28
29pub const EXPIRATION: i64 = 10 * 365 * 24 * 60 * 60; fn jwt_secret() -> &'static Vec<u8> {
34 static SECRET: OnceCell<Vec<u8>> = OnceCell::new();
35 SECRET.get_or_init(|| {
36 let seed: [u8; 16] = thread_rng().gen();
37 seed.to_vec()
38 })
39}
40
41#[derive(Debug, Deserialize, Serialize)]
43pub struct Claims {
44 sub: String,
46 iat: i64,
48 exp: i64,
50}
51
52impl Claims {
53 pub fn new<N: Network>(address: Address<N>) -> Self {
54 let issued_at = OffsetDateTime::now_utc().unix_timestamp();
55 let expiration = issued_at.saturating_add(EXPIRATION);
56
57 Self { sub: address.to_string(), iat: issued_at, exp: expiration }
58 }
59
60 pub fn is_expired(&self) -> bool {
62 OffsetDateTime::now_utc().unix_timestamp() >= self.exp
63 }
64
65 pub fn to_jwt_string(&self) -> Result<String> {
67 encode(&Header::default(), &self, &EncodingKey::from_secret(jwt_secret())).map_err(|e| anyhow!(e))
68 }
69}
70
71pub fn with_auth() -> impl Filter<Extract = ((),), Error = Rejection> + Clone {
73 warp::header::<String>("authorization").and_then(|token: String| async move {
74 if !token.starts_with("Bearer ") {
75 return Err(reject::custom(RestError::Request("Invalid authorization header.".to_string())));
76 }
77
78 match decode::<Claims>(
80 token.trim_start_matches("Bearer "),
81 &DecodingKey::from_secret(jwt_secret()),
82 &Validation::new(Algorithm::HS256),
83 ) {
84 Ok(decoded) => {
85 let claims = decoded.claims;
86 if claims.is_expired() {
87 return Err(reject::custom(RestError::Request("Expired JSON Web Token.".to_string())));
88 }
89
90 Ok(())
91 }
92 Err(_) => Err(reject::custom(RestError::Request("Unauthorized caller.".to_string()))),
93 }
94 })
95}