1
use crate::error::{Error, Result};
2
use actix_http::{HttpMessage, Payload};
3
use actix_web::{error::ErrorInternalServerError, FromRequest, HttpRequest};
4
use jsonwebtoken::{decode, DecodingKey, Validation};
5
use serde::{Deserialize, Serialize};
6
use std::{
7
    future::{ready, Ready},
8
    path::Path,
9
};
10

            
11
#[derive(Debug, Serialize, Deserialize, Clone)]
12
pub struct Claims {
13
    pub username: String,
14
    pub organization: String,
15
    pub email: String,
16
    pub exp: u64,
17
}
18

            
19
/// An implementaion of `FromRequest` makes it possible to extract the
20
/// claims the request handling signature.
21
impl FromRequest for Claims {
22
    type Error = actix_web::Error;
23
    type Future = Ready<std::result::Result<Claims, actix_web::Error>>;
24

            
25
    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
26
        Self::extract(req)
27
    }
28

            
29
    fn extract(req: &HttpRequest) -> Self::Future {
30
        let ext = req.extensions();
31
        match ext.get::<Claims>() {
32
            Some(claims) => ready(Ok(claims.clone())),
33
            None => ready(Err(ErrorInternalServerError(
34
                "No JWT claims were present.".to_string(),
35
            ))),
36
        }
37
    }
38
}
39

            
40
pub fn validate_token(token: &str, jwt_secret: &[u8]) -> Result<Claims> {
41
    let validation = Validation::default();
42
    let token = decode::<Claims>(token, &DecodingKey::from_secret(jwt_secret), &validation)?;
43
    Ok(token.claims)
44
}
45

            
46
9
pub fn load_jwks(path: &Path) -> Result<Jwks> {
47
9
    let path = path.join("jwt_secret");
48
9
    let bytes = std::fs::read(&path).map_err(|e| Error::Io {
49
        source: e,
50
        path: path.clone(),
51
9
    })?;
52
9
    let content = String::from_utf8(bytes)
53
9
        .map_err(|e| Error::Utf8 { source: e, path })?
54
9
        .trim()
55
9
        .to_string();
56
9
    Ok(Jwks { secret: content })
57
9
}
58

            
59
#[derive(Clone)]
60
pub struct Jwks {
61
    secret: String,
62
}
63

            
64
impl Jwks {
65
    pub fn secret(&self) -> &[u8] {
66
        self.secret.as_bytes()
67
    }
68
}