Started adding doc to better build the system

This commit is contained in:
2025-04-09 22:48:11 +02:00
parent 9347db69fd
commit 2ffe9c0c2b

View File

@@ -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};
@@ -81,36 +107,37 @@ async fn logout(
req: HttpRequest,
app_state: Data<AppState>,
) -> Result<impl Responder, Box<(dyn Error + 'static)>> {
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::<UserTokenClaims>(
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::<UserTokenClaims>(
// 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")]
@@ -147,31 +174,32 @@ async fn verify_token(
app_state: Data<AppState>,
token: &str,
) -> Result<bool, Box<(dyn Error + 'static)>> {
let mut key = File::open("pub.pem")?;
let mut buf = vec![];
key.read_to_end(&mut buf)?;
let token = decode::<UserTokenClaims>(
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::<UserTokenClaims>(
// 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)
}