use argon2rs::argon2i_simple;
use async_trait::async_trait;
use chrono::{Duration, Utc};
use fistinc_errors::{CommonError, ServiceResult};
use jsonwebtoken;
use crate::domain::entity::Token;
use crate::domain::entity::User;
use crate::domain::services::UserSecurityService;
pub struct UserSecurityServiceImpl {
pub salt: String,
pub jwt_key: String,
pub expire_duration: Duration,
}
impl UserSecurityServiceImpl {
pub fn new(salt: &str, jwt_key: &str, expire_duration: Duration) -> Self {
UserSecurityServiceImpl {
salt: salt.to_string(),
jwt_key: jwt_key.to_string(),
expire_duration,
}
}
}
#[async_trait]
impl UserSecurityService for UserSecurityServiceImpl {
async fn hash(&self, input: &str) -> ServiceResult<String> {
let result = argon2i_simple(&input, &self.salt)
.iter()
.map(|b| format!("{:02x}", b))
.collect();
Ok(result)
}
async fn verify_hash(&self, hashed: &str, raw: &str) -> ServiceResult<bool> {
let hashed_curr = self.hash(raw).await?;
Ok(hashed_curr == hashed)
}
async fn token_generator(&self, user: &User) -> ServiceResult<String> {
let claim = Token {
email: user.email.clone(),
role: user.role,
expire: Utc::now() + self.expire_duration,
};
let encoding_key = jsonwebtoken::EncodingKey::from_secret(self.jwt_key.as_ref());
let token = jsonwebtoken::encode(
&jsonwebtoken::Header::default(),
&claim,
&encoding_key,
)
.map_err(|e| CommonError {
message: e.to_string(),
code: 500,
})?;
Ok(token)
}
async fn decode_token(&self, token: &str) -> ServiceResult<Token> {
let decoding_key = jsonwebtoken::DecodingKey::from_secret(self.jwt_key.as_ref());
jsonwebtoken::decode::<Token>(
token,
&decoding_key,
&jsonwebtoken::Validation::default(),
)
.map(|data| data.claims)
.map_err(|e| CommonError {
message: e.to_string(),
code: 403,
})
}
}