diff --git a/src/users.rs b/src/users.rs index 090a7ca..e73b57c 100644 --- a/src/users.rs +++ b/src/users.rs @@ -1,3 +1,29 @@ +//! # Authentication flow +//! Before being able to authenticate, the user needs to create an account +//! Here's how it can be done: +//! - The user submits information on the client +//! - The client sends a request to the "register" endpoint +//! - The endpoint ensures the information given is valid +//! - An account is created +//! - The user is redirected to the login page +//! +//! After, the user can authenticate +//! Here's how it works: +//! - The users submits information on the client +//! - The client sends a request to the "login" endpoint +//! - The endpoint makes sure the information given is valid (otherwise reject the request: no db call) +//! - Then it checks that the user exists +//! - Then it checks that the correct password was given +//! - Then it creates two tokens: a short-lived and a refresh-token +//! - The short-lived token must be saved in local-storage and the refresh-token must be saved as a http only cookie +//! +//! Once authenticated, the short-lived token can be renewed +//! Here's how it works: +//! - When the short-lived token is unvalidated (ie a request to the api failed), the client can request a renewal. +//! - The renewal request contains the now unvalid token with the refresh-token cookie. +//! - The server checks that the refresh-token is valid (good user, not expired, ...) +//! - If checks pass, the server generates a new short-lived token. +//! - If it fails, the client redirects the user to login. use crate::AppState; use crate::types::{User, UserLogin, UserRegister, UserTokenClaims}; use actix_web::web::{Data, Json}; @@ -37,8 +63,8 @@ async fn login( "SELECT * FROM users WHERE username = $1", user_login.username ) - .fetch_optional(&app_state.database) - .await? + .fetch_optional(&app_state.database) + .await? { Some(user) => { let hash = PasswordHash::new(&user.hash)?; @@ -81,36 +107,37 @@ async fn logout( req: HttpRequest, app_state: Data, ) -> Result> { + todo!(); // Put the (KeyId, User) pair in the revoked table // And remove data from client - match req.headers().get("Authorization") { - Some(token) => { - let token = token.to_str()?; - let token = match token.split_once(" ") { - Some((_, token)) => token, - None => return Ok(HttpResponse::BadRequest().finish()), - }; - let mut key = File::open("pub.pem")?; - let mut buf = vec![]; - key.read_to_end(&mut buf)?; - let token = decode::( - token, - &DecodingKey::from_ec_pem(&buf).unwrap(), - &Validation::new(Algorithm::ES256), - )?; - let exp = token.claims.exp as i64; - query!( - "INSERT INTO revoked ( token_id, user_id, expires ) VALUES ( $1, $2, $3 )", - token.claims.kid, - token.claims.uid, - exp - ) - .execute(&app_state.database) - .await?; - Ok(HttpResponse::Ok().finish()) - } - None => Ok(HttpResponse::BadRequest().finish()), - } + // match req.headers().get("Authorization") { + // Some(token) => { + // let token = token.to_str()?; + // let token = match token.split_once(" ") { + // Some((_, token)) => token, + // None => return Ok(HttpResponse::BadRequest().finish()), + // }; + // let mut key = File::open("pub.pem")?; + // let mut buf = vec![]; + // key.read_to_end(&mut buf)?; + // let token = decode::( + // token, + // &DecodingKey::from_ec_pem(&buf).unwrap(), + // &Validation::new(Algorithm::ES256), + // )?; + // let exp = token.claims.exp as i64; + // query!( + // "INSERT INTO revoked ( token_id, user_id, expires ) VALUES ( $1, $2, $3 )", + // token.claims.kid, + // token.claims.uid, + // exp + // ) + // .execute(&app_state.database) + // .await?; + // Ok(HttpResponse::Ok().finish()) + // } + // None => Ok(HttpResponse::BadRequest().finish()), + // } } #[post("/register")] @@ -138,8 +165,8 @@ async fn register( hash, user_register.email ) - .execute(&app_state.database) - .await?; + .execute(&app_state.database) + .await?; Ok(HttpResponse::Ok().finish()) } @@ -147,31 +174,32 @@ async fn verify_token( app_state: Data, token: &str, ) -> Result> { - let mut key = File::open("pub.pem")?; - let mut buf = vec![]; - key.read_to_end(&mut buf)?; - let token = decode::( - token, - &DecodingKey::from_ec_pem(&buf).unwrap(), - &Validation::new(Algorithm::ES256), - )?; - let exp = token.claims.exp as u64; - let now = get_current_timestamp(); - if exp > now { - return Ok(false); - } - let kid = token.claims.kid; - let uid = token.claims.uid; - if query!( - "SELECT token_id FROM revoked WHERE token_id = $1 AND user_id = $2", - kid, - uid - ) - .fetch_optional(&app_state.database) - .await? - .is_some() - { - return Ok(false); - } - Ok(true) + todo!(); + // let mut key = File::open("pub.pem")?; + // let mut buf = vec![]; + // key.read_to_end(&mut buf)?; + // let token = decode::( + // token, + // &DecodingKey::from_ec_pem(&buf).unwrap(), + // &Validation::new(Algorithm::ES256), + // )?; + // let exp = token.claims.exp as u64; + // let now = get_current_timestamp(); + // if exp > now { + // return Ok(false); + // } + // let kid = token.claims.kid; + // let uid = token.claims.uid; + // if query!( + // "SELECT token_id FROM revoked WHERE token_id = $1 AND user_id = $2", + // kid, + // uid + // ) + // .fetch_optional(&app_state.database) + // .await? + // .is_some() + // { + // return Ok(false); + // } + // Ok(true) }