Can get user information

This commit is contained in:
2023-05-31 15:52:49 +02:00
parent 652541cd59
commit c0f120bb53
7 changed files with 98 additions and 9 deletions

View File

@ -4,18 +4,20 @@ use crate::connections::redis_connection;
use crate::models::{User, UserID};
use crate::utils::string_utils;
use crate::utils::time_utils::time;
use actix_web::dev::Payload;
use actix_web::{FromRequest, HttpRequest};
use std::time::Duration;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
struct LoginToken {
pub struct LoginToken {
expire: u64,
hb: u64,
user_id: UserID,
pub user_id: UserID,
}
impl LoginToken {
pub fn new(user: &User) -> (String, Self) {
let key = format!("tok-{}-{}", user.id().0, string_utils::rand_str(40));
let key = format!("{}-{}", user.id().0, string_utils::rand_str(40));
(
key,
@ -27,8 +29,8 @@ impl LoginToken {
)
}
pub fn is_valid(&self) -> bool {
self.expire > time() && self.hb + 3600 > time()
pub fn is_expired(&self) -> bool {
self.expire < time() || self.hb + 3600 < time()
}
pub fn refresh_hb(&self) -> Option<Self> {
@ -41,7 +43,7 @@ impl LoginToken {
}
}
pub fn lifetime(&self) -> Duration {
pub fn redis_lifetime(&self) -> Duration {
Duration::from_secs(if self.expire <= time() {
0
} else {
@ -50,9 +52,73 @@ impl LoginToken {
}
}
/// Get redis key for a given login token
fn redis_key(tok: &str) -> String {
format!("tok-{tok}")
}
/// Generate a new login token
pub async fn gen_new_token(user: &User) -> anyhow::Result<String> {
let (key, token) = LoginToken::new(user);
redis_connection::set_value(&key, &token, token.lifetime()).await?;
redis_connection::set_value(&redis_key(&key), &token, token.redis_lifetime()).await?;
Ok(key)
}
/// Get a user information from its token
async fn get_token(key: &str) -> anyhow::Result<Option<LoginToken>> {
let token = match redis_connection::get_value::<LoginToken>(&redis_key(key)).await? {
None => {
log::error!("Could not find token for key '{}' (key absent)", key);
return Ok(None);
}
Some(t) => t,
};
if token.is_expired() {
log::error!("Could not find token for key '{}' (token expired)", key);
return Ok(None);
}
// Check if heartbeat must be updated
if let Some(renew) = token.refresh_hb() {
redis_connection::set_value(&redis_key(key), &renew, renew.redis_lifetime()).await?;
}
Ok(Some(token))
}
impl FromRequest for LoginToken {
type Error = actix_web::Error;
type Future = futures_util::future::LocalBoxFuture<'static, Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
let req = req.clone();
Box::pin(async move {
let token = match req.headers().get("X-Auth-Token") {
Some(v) => v.to_str().unwrap_or(""),
None => {
return Err(actix_web::error::ErrorBadRequest(
"Missing auth token header!",
));
}
};
let token = match get_token(token).await {
Err(e) => {
log::error!("Failed to load auth token! {}", e);
return Err(actix_web::error::ErrorInternalServerError(
"Failed to check auth token!",
));
}
Ok(None) => {
return Err(actix_web::error::ErrorPreconditionFailed(
"Invalid auth token!",
));
}
Ok(Some(t)) => t,
};
Ok(token)
})
}
}