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, PartialEq, Eq)]
pub struct Claims {
pub exp: u64,
pub claims: HashMap<String, String>, }
#[derive(Debug)]
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,
}
}