1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use chrono::{prelude::Utc, Duration};
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::errors::*;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Claims {
pub exp: u64,
pub claims: HashMap<String, String>,
}
pub struct JWTSecret<'a> {
encoding_key: EncodingKey,
decoding_key: DecodingKey<'a>,
}
pub fn get_jwt_secret<'a>(secret_str: String) -> Result<JWTSecret<'a>> {
let encoding_key = EncodingKey::from_base64_secret(&secret_str)?;
let decoding_key = DecodingKey::from_base64_secret(&secret_str)?;
Ok(JWTSecret {
encoding_key,
decoding_key,
})
}
pub fn decode_time_str(time_str: &str) -> Result<u64> {
let mut duration_after_current = Duration::zero();
let current = Utc::now();
let mut curr_duration_length = String::new();
for c in time_str.chars() {
if c.is_numeric() {
curr_duration_length.push(c);
} else {
let interval_length = curr_duration_length.parse::<i64>().unwrap();
let duration = match c {
's' => Duration::seconds(interval_length),
'm' => Duration::minutes(interval_length),
'h' => Duration::hours(interval_length),
'd' => Duration::days(interval_length),
'w' => Duration::weeks(interval_length),
'M' => Duration::days(interval_length * 30),
'y' => Duration::days(interval_length * 365),
c => bail!(ErrorKind::InvalidDatetimeIntervalIndicator(c.to_string())),
};
duration_after_current = duration_after_current + duration;
curr_duration_length = String::new();
}
}
let datetime = current + duration_after_current;
Ok(datetime.timestamp() as u64)
}
pub fn create_jwt(
user_claims: HashMap<String, String>,
secret: &JWTSecret,
exp: u64,
) -> Result<String> {
let claims = Claims {
exp,
claims: user_claims,
};
let token = encode(
&Header::new(Algorithm::HS512),
&claims,
&secret.encoding_key,
)?;
Ok(token)
}
pub fn validate_and_decode_jwt(jwt: &str, secret: &JWTSecret) -> Option<Claims> {
let decoded = decode::<Claims>(
jwt,
&secret.decoding_key,
&Validation::new(Algorithm::HS512),
);
match decoded {
Ok(decoded) => Some(decoded.claims),
Err(_) => None,
}
}