mirror of
https://github.com/MedzikUser/HomeDisk.git
synced 2024-08-14 21:46:53 +00:00
115 lines
2.7 KiB
Rust
115 lines
2.7 KiB
Rust
|
use chrono::{Duration, Utc};
|
||
|
use jsonwebtoken::{
|
||
|
decode, encode, errors::Error, Algorithm, DecodingKey, EncodingKey, Header, TokenData,
|
||
|
Validation,
|
||
|
};
|
||
|
use serde::{Deserialize, Serialize};
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
|
pub struct Claims {
|
||
|
pub sub: String,
|
||
|
pub exp: i64,
|
||
|
pub iat: i64,
|
||
|
}
|
||
|
|
||
|
impl Claims {
|
||
|
/// Generate Json Web Token Claims
|
||
|
/// ```
|
||
|
/// use homedisk_types::token::Claims;
|
||
|
///
|
||
|
/// let user_id = "123".to_string();
|
||
|
/// let claims = Claims::new(user_id);
|
||
|
/// ```
|
||
|
pub fn new(sub: String) -> Self {
|
||
|
let iat = Utc::now();
|
||
|
let exp = iat + Duration::hours(24);
|
||
|
|
||
|
Self {
|
||
|
sub,
|
||
|
iat: iat.timestamp(),
|
||
|
exp: exp.timestamp(),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
|
pub struct Token {
|
||
|
header: Header,
|
||
|
pub claims: Claims,
|
||
|
pub encoded: String,
|
||
|
}
|
||
|
|
||
|
impl Token {
|
||
|
/// Generate new token
|
||
|
/// ```ignore
|
||
|
/// use homedisk_types::token::{Token, Claims};
|
||
|
///
|
||
|
/// let claims = Claims::new("user_id_1234".to_string());
|
||
|
/// let token = Token::new(secret, claims)?;
|
||
|
/// ```
|
||
|
pub fn new(key: &[u8], claims: Claims) -> Result<Self> {
|
||
|
let header = Header::new(Algorithm::HS256);
|
||
|
let encoded = encode(&header, &claims, &EncodingKey::from_secret(key))?;
|
||
|
|
||
|
Ok(Self {
|
||
|
header,
|
||
|
claims,
|
||
|
encoded,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/// Validate token
|
||
|
/// ```ignore
|
||
|
/// use homedisk_types::token::{Token, Claims};
|
||
|
///
|
||
|
/// let token = Token::new(secret, claims)?;
|
||
|
/// let decoded = Token::decode(secret, token.encoded)?;
|
||
|
/// ```
|
||
|
pub fn decode(key: &[u8], token: String) -> Result<TokenData<Claims>> {
|
||
|
decode::<Claims>(
|
||
|
&token,
|
||
|
&DecodingKey::from_secret(key),
|
||
|
&Validation::default(),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod test {
|
||
|
use super::{Claims, Token};
|
||
|
|
||
|
fn gen_token(key: &[u8]) -> Token {
|
||
|
Token::new(key, Claims::new("test".to_string())).expect("generate token")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn new_token() {
|
||
|
let key = b"secret";
|
||
|
gen_token(key);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn decode_token() {
|
||
|
let key = b"secret";
|
||
|
let token = gen_token(key);
|
||
|
|
||
|
let decoded = Token::decode(key, token.encoded).unwrap();
|
||
|
|
||
|
assert_eq!(decoded.claims, token.claims)
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn decode_token_invalid_token() {
|
||
|
let key = b"key";
|
||
|
let token = gen_token(key);
|
||
|
|
||
|
let other_key = b"other key";
|
||
|
|
||
|
let err = Token::decode(other_key, token.encoded).unwrap_err();
|
||
|
|
||
|
assert_eq!(err.to_string(), "InvalidSignature");
|
||
|
}
|
||
|
}
|