diff --git a/db/auth.sqlite b/db/auth.sqlite index 4e846d8..0662d3b 100644 Binary files a/db/auth.sqlite and b/db/auth.sqlite differ diff --git a/db/auth copy 2.sqlite b/db/auth_copy_2.sqlite similarity index 85% rename from db/auth copy 2.sqlite rename to db/auth_copy_2.sqlite index 978d5ed..312fa53 100644 Binary files a/db/auth copy 2.sqlite and b/db/auth_copy_2.sqlite differ diff --git a/db/auth.sqlite-shm b/db/auth_copy_2.sqlite-shm similarity index 95% rename from db/auth.sqlite-shm rename to db/auth_copy_2.sqlite-shm index c1b1e8d..9c010b0 100644 Binary files a/db/auth.sqlite-shm and b/db/auth_copy_2.sqlite-shm differ diff --git a/db/auth.sqlite-wal b/db/auth_copy_2.sqlite-wal similarity index 72% rename from db/auth.sqlite-wal rename to db/auth_copy_2.sqlite-wal index 52711c3..26eb4de 100644 Binary files a/db/auth.sqlite-wal and b/db/auth_copy_2.sqlite-wal differ diff --git a/src/main.rs b/src/main.rs index 501c9e4..7ab429b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,7 @@ std::panic::set_hook(Box::new(|info| { //panic!("crash-test"); let hotel_pools = HotelPool::new(); - let logs_manager = SqliteConnectionManager::file("db/auth.sqlite"); + let logs_manager = SqliteConnectionManager::file("db/auth_copy_2.sqlite"); let logs_pool = Pool::builder() .max_size(5) .build(logs_manager) diff --git a/src/utils/auth.rs b/src/utils/auth.rs index b529381..1a48ecf 100644 --- a/src/utils/auth.rs +++ b/src/utils/auth.rs @@ -175,7 +175,7 @@ pub struct ForceUpdatePasswordValues{ //pub struct ForceUpdatePasswordPayload (pub ForceUpdatePasswordValues); -pub async fn ForceUpdatePassword( +pub async fn force_update_password( State(state): State, Json(payload): Json, ) -> impl IntoResponse { @@ -191,7 +191,7 @@ pub async fn ForceUpdatePassword( |row|{ let user_id: i32 = row.get(0)?; //let hotel_id: i32 = row.get(1)?; - Ok((user_id)) + Ok(user_id) }, ).optional() { Ok(opt) => opt, @@ -199,7 +199,7 @@ pub async fn ForceUpdatePassword( .into_response(), }; - let (user_id) = match user_row { + let user_id = match user_row { Some(u) => u, None => return (StatusCode::UNAUTHORIZED, "Not correct user") .into_response(), @@ -239,7 +239,7 @@ pub struct UpdatePasswordValues{ } -pub async fn UpdatePassword( +pub async fn update_password( State(state): State, Json(payload): Json, ) -> impl IntoResponse { @@ -360,7 +360,7 @@ pub async fn clean_auth_loging( Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), }; - let (user_id, stored_hash, hotel_id, displayname) = match user_row { + let (user_id, stored_hash, hotel_id, _displayname) = match user_row { Some(u) => u, None => return (StatusCode::UNAUTHORIZED, "Invalid credentials").into_response(), }; @@ -405,7 +405,9 @@ pub struct CreateRefreshTokenValue { } -//TODO: refactor this to impl IntoResponse ans not Result + +//FIXME: weird return type, returning result ? + #[axum::debug_handler] pub async fn create_refresh_token( State(state): State, @@ -433,26 +435,76 @@ pub async fn create_refresh_token( let conn = state.logs_pool.get() .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "DB connection error".to_string()))?; - let mut stmt = conn.prepare( - "SELECT id, password, hotel_id FROM users WHERE username = ?1" - ).map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "DB prepare error".to_string()))?; + //TODO: prend id username password de users + // let mut stmt = conn.prepare( + // "SELECT id, password FROM users WHERE username = ?1" - let user_rows = stmt - .query_map(params![&payload.username], |row| { + let credentials = match conn.query_row( + "SELECT id, password FROM users WHERE username = ?1", + params![&payload.username], + |row| { let user_id: i32 = row.get(0)?; let password: String = row.get(1)?; - let hotel_id: i32 = row.get(2)?; - Ok((user_id, password, hotel_id)) - }) - .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "DB query error".to_string()))?; + Ok((user_id, password)) + }, + ) { + Ok(cr) => cr, + Err(_) => return Err((StatusCode::INTERNAL_SERVER_ERROR, "error fetching credentials".to_string())), + + }; + + let (user_id, user_password) = credentials; /* let (user_id, stored_hash, hotel_id) = user_row .ok_or((StatusCode::NOT_FOUND, "User not found".to_string()))?; */ //let mut tokens = Vec::new(); + //TODO: validate password + if !verify_password(&payload.password, &user_password) { + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Invalid credential".to_string())); // Skip rows with invalid password + } + + + //TODO: stmt, querry hotel-id dans hotel-user-link avec l'ID précédant + let mut stmt = match conn.prepare( + "SELECt hotel_id FROM hotel_user_link WHERE user_id = ?1" + ) { + Ok(stmt) => stmt, + Err(_) => return Err((StatusCode::INTERNAL_SERVER_ERROR, "error building user_id fetch stmt".to_string())), + }; + //TODO: compiler les hotel id dans un vecteur pour le feed dans le refresh token + //Deja fait ? + + + + + let hotel_ids = match stmt + .query_map(params![&user_id],|row| row.get (0)) + { + Ok(rows) => rows.collect::,_>>() + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error collecting hotel_ids".to_string()))?, + Err(_) => return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error mapping hotel_ids".to_string())), + }; + + + conn.execute( + "INSERT INTO refresh_token (user_id, token_hash, device_id, user_agent, hotel_id_list) + VALUES (?1, ?2, ?3, ?4, ?5)", + params![ + &user_id, + &hashed_token, + &device_id_str, + &user_agent_str, + &hotel_ids, + ], + ).map_err(|e| { + (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {}", e)) + })?; + //TODO: insert single refresh token + /* for user_row_result in user_rows { let (user_id, stored_hash, hotel_id) = user_row_result .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "DB row error".to_string()))?; @@ -480,7 +532,8 @@ pub async fn create_refresh_token( //tokens.push(raw_token); } - + + */ let cookie_value = format!("refresh_token={}; HttpOnly; Secure; Path=/", raw_token); @@ -499,6 +552,7 @@ pub struct LoginRefreshTokenValues{ refresh_token: String, } +//TODO: LATER : implement hotel-id-selected to allow user to only get part hotels ? pub async fn login_refresh_token ( State(state): State, Extension(keys): Extension, @@ -519,16 +573,19 @@ pub async fn login_refresh_token ( let device_id_str = payload.device_id.to_string(); */ -let user_agent_str = match user_agent { - Some(ua) => ua.to_string(), - None => return (StatusCode::INTERNAL_SERVER_ERROR, "user agent unknown").into_response(), -}; + let user_agent_str = match user_agent { + Some(ua) => ua.to_string(), + None => return (StatusCode::INTERNAL_SERVER_ERROR, "user agent unknown").into_response(), + }; -let device_id_str = payload.device_id.to_string(); + let device_id_str = payload.device_id.to_string(); //"SELECT user_id, token_hash, hotel_id FROM refresh_token WHERE device_id = ?1 AND user_agent = ?2", + //TODO: swap to query row and get hotel-id's list and not single hotel per row + //deserializing the list : + //let hotel_ids: Vec = serde_json::from_str(&stored_value)?; let mut stmt = match conn.prepare( "SELECT user_id, token_hash, hotel_id FROM refresh_token @@ -549,6 +606,8 @@ let device_id_str = payload.device_id.to_string(); Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), }; + + let mut entries = Vec::new(); for r in rows { match r { @@ -563,34 +622,35 @@ let device_id_str = payload.device_id.to_string(); let mut tokens = Vec::new(); -for (user_id, token_hash, hotel_id) in entries { - if !verify_password(&payload.refresh_token, &token_hash) { - // skip rows with wrong hash - continue; + //FIXME: swap to "for hotel_id in entries" // interator over vector list + for (user_id, token_hash, hotel_id) in entries { + if !verify_password(&payload.refresh_token, &token_hash) { + // skip rows with wrong hash + continue; + } + //FIXME: single expiration + let expiration = match chrono::Utc::now().checked_add_signed(chrono::Duration::hours(15)) { + Some(time) => time.timestamp() as usize, + None => { + // Handle overflow — probably a 500, since this should never happen + return (StatusCode::INTERNAL_SERVER_ERROR, "Time overflow".to_string()).into_response(); + } + }; + + let claims = serde_json::json!({ + "id": user_id, + "hotel_id": hotel_id, + "exp": expiration + }); + + let token = match encode(&Header::default(), &claims, &keys.encoding) { + Ok(t) => t, + Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "JWT creation failed").into_response(), + }; + + tokens.push(token); } - let expiration = match chrono::Utc::now().checked_add_signed(chrono::Duration::hours(15)) { - Some(time) => time.timestamp() as usize, - None => { - // Handle overflow — probably a 500, since this should never happen - return (StatusCode::INTERNAL_SERVER_ERROR, "Time overflow".to_string()).into_response(); - } - }; - - let claims = serde_json::json!({ - "id": user_id, - "hotel_id": hotel_id, - "exp": expiration - }); - - let token = match encode(&Header::default(), &claims, &keys.encoding) { - Ok(t) => t, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "JWT creation failed").into_response(), - }; - - tokens.push(token); -} - if tokens.is_empty() { return (StatusCode::UNAUTHORIZED, "Invalid or mismatched token").into_response(); diff --git a/src/utils/routes.rs b/src/utils/routes.rs index 99ad04a..1e47221 100644 --- a/src/utils/routes.rs +++ b/src/utils/routes.rs @@ -18,8 +18,8 @@ pub fn utils_routes() -> Router { .route("/register", put(register_user)) .route("/ws/", get(ws_handler)) .route("/tokentest", put(token_tester)) - .route("/force_update_password", put(ForceUpdatePassword)) - .route("/update_password", put(UpdatePassword)) + .route("/force_update_password", put(force_update_password)) + .route("/update_password", put(update_password)) .route("/create_refresh", post(create_refresh_token)) .route("/login_refresh_token", post(login_refresh_token))