From 02c11137ffa22f15260e18bfa5b66ce4a8f28eae Mon Sep 17 00:00:00 2001 From: Romain Mallard Date: Fri, 28 Nov 2025 20:48:46 +0100 Subject: [PATCH] fix get refresh token handler and update login refresh token --- db/auth_copy_2.sqlite | Bin 65536 -> 73728 bytes db/auth_copy_2.sqlite-shm | Bin 32768 -> 32768 bytes db/auth_copy_2.sqlite-wal | Bin 238992 -> 12392 bytes src/main.rs | 2 +- src/utils/auth.rs | 87 +++++++++++++++++++++++++++----------- 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/db/auth_copy_2.sqlite b/db/auth_copy_2.sqlite index 312fa53d20585e7576c5233f4baf807e4e931218..80bbf23bc48ead44ae95ff49375a1b7bee50bd30 100644 GIT binary patch delta 1720 zcmdT^O>7%Q6yDicuf4W+pPe?@n6$PN5**j4{-X{SiXz8xNSeReajNEmaS~Iz{!45} zi3>_%D;J;#+C5TnpeMws7^%G!iU<;i(jXxyqD2vHDpja~3XxJl56s$0i2-qES2MeM z^Sy80zVDk|Sz%VLGHl@{$djed}_f`^4iRH{}zq1dTjLxMfEln;PGT1Gg}2p8ZC z7=-f`y}2kzuN(I%6<9&>JYTtBj1makr{FO>f?wc1f!u<21x5&Cd8TQMISyl$N=@v* zzy<{yumzj&kRaDV!C)R?X|u;nHd>?L4>$y8g*CGFp-@>H^`IuEirAC9EvN5Eu53o` zLBA5)Q7-mME|!l+3fW{V6Dg!;S-lcl>ccFDu!v-h^Oz?UQ96o(i14vs;$PE#SJCS} z*J?{9mZMaqu?d?_C0#U{{0m*vv%W;|WM;xXJ{>+XH=GOxdV}qQ9$Utq8FmyylMZ(# zIS`)7O;5#a@vijoq4e>QcxW&gK9RHAx=v2dNY|HL0-{T1#SV2tjXK|T>iL2<-sf0c zIPLJnC*t;EYB<=Q4i?Ayhg<{h)YMqWAGP%jWR4B_7wrY_bE89vK4<@&r!>{lY+=JV4;K@}nnm+}H z>;#sTXN5wZ8AhIW9U|+X(B7cnCE<#2fG=uq5FI}IU+Mrvhmw)m(HN>4OGlUHd1uLp z>!Uv|%?r+wiRLIITMbmS>^14l<#}+*O~vp)K2;Cl0TJ>Rbh22FTxtad{3OGG=nT+ylHaOz(JCx*E+?t*PsL)l7XSbN delta 854 zcmZuwOHUI~6rMYGN;|K6I=qHbgo-A_j**ro?2G|zjHCe{HNn+T!x$>G6{bEC6I03x zDq)157L6hdmGjdN>$U7-2MI9}; z9GEP(hy8jYftDtUnd@`bOrdDanYV3g!JNzHXU$^nR+E%?_HuG0os6VMMpMbiRFjG+ z`c^thpNJE*E)LRHqSBque=j zC_8=pj`9SnfG-HpYihyO^2IW%GX_UtCZF;#AF#Fxr9#(Smhj!Lnz}Vqw^@NFQ4ijW~S|J|Lb8dWu)V#3S71;5&SV?M9mJ)P4Pe z;KK-E>^^zkt>R(dwY$$=6&9jbTdVt9J;!cMW0U{fRaQC_6}B00or86F&)lp*M<)`* z0o_}VxOpynlYP@TeZAAu%iyiyKQ}}1SS;qz);RbIwFVvgL1=ADKQz$qLktE7b~=6o DRs#2V diff --git a/db/auth_copy_2.sqlite-shm b/db/auth_copy_2.sqlite-shm index 9c010b0f93a6400ccd0d901aad22e4174a0400c3..3564af8b6c553ad8d593abf46193863c8a81466c 100644 GIT binary patch delta 184 zcmZo@U}|V!s+V}A%K!q55G=q9q=kU^9?x=xgJKU<1dMyhq~q+#=Zd-M8y(Y<@Rzq&j-fBblOxqd5m+V$oyuaEbR z_Weq%WF8$4*bLcJZ0tGIXESJ1wW-?V_ zP?L@bqzDx3oy=8@XjSXl)V6lCrvtT9t|UU>zX_ZudJ8)X0gnP1&3UX%X9P^3XkWUh zX;f?4(3V=-)xHjqLBNGTR`V`;QWAksAg6^eBtgK1K*_!%R@ayoU9_bn0!e|geO0fa laV;f7juCJnuWWEdl@l diff --git a/db/auth_copy_2.sqlite-wal b/db/auth_copy_2.sqlite-wal index 26eb4de948dc8640b920a69ac8cfa8fb4a8b41e3..3f04b9d6cac4845db6ba0325038ccee4d584060e 100644 GIT binary patch delta 446 zcmbPmn(sw|g?T+&6NBy}2?hoM1`v?B_xP$`)lr4nIT@M78B2>(i;9_nrg0;i zcyInBfvDPPoxDInHXb7e{y4t9d@{V1JlA=QHU`S^@H8s1b24x=`iE+Zb4(X(WR!PK z@yIsK^zk+g%5Zdv^7L|cO3oJHa8C?yOExi1%#X|q@G-UY)DHAA z4k}Ix^z#k#Er~Gq_B5P+U=p*DV6>r*QEa0;8`OLOi22)VCoxMia?7zmh4~@E)02Xk zOL+|&<(SdLnL?OL`3xK7nK&63LC)moU;?{y`eLAjt|8E0AioL0f>vQU&%GOW&K~3f zd6@qW1OG4nFZ}QLU+_QTzq2v$1iuO^Gb1BAJBVas1Cgw(Ad-azL^3mjNG2u#<;Zt~ literal 238992 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 = match stmt .query_map(params![&user_id],|row| row.get (0)) { Ok(rows) => rows.collect::,_>>() @@ -489,6 +486,13 @@ pub async fn create_refresh_token( Err(_) => return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error mapping hotel_ids".to_string())), }; + let hotel_ids_json = match serde_json::to_string(&hotel_ids) { + Ok(json) => json, + Err(_) => return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error mapping hotel_ids".to_string())), + }; + + + /*.map_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) @@ -498,7 +502,7 @@ pub async fn create_refresh_token( &hashed_token, &device_id_str, &user_agent_str, - &hotel_ids, + &hotel_ids_json, ], ).map_err(|e| { (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {}", e)) @@ -587,27 +591,35 @@ pub async fn login_refresh_token ( //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 + "SELECT user_id, token_hash, hotel_id_list FROM refresh_token - WHERE device_id = ?1 AND user_agent = ?2" + WHERE device_id = ?1 AND user_agent = ?2 " ) { Ok(s) => s, Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), }; - let rows = match stmt.query_map(params![&device_id_str, &user_agent_str], |row| { + let rows = match stmt.query_one(params![&device_id_str, &user_agent_str], |row| { Ok(( row.get::<_, i32>(0)?, // user_id row.get::<_, String>(1)?, // token_hash - row.get::<_, i32>(2)?, // hotel_id + row.get::<_, String>(2)?, // hotel_id //FIXME: this is supposed to be vectore maybe ? )) }) { Ok(r) => r, Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), }; + //TODO: extraction of the blob + //let json_hotel_ids = rows.2; + let (user_id, saved_hash,json_hotel_ids) = rows; + let hotel_ids: Vec = match serde_json::from_str(&json_hotel_ids) { + Ok(ids) => ids, + Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "Hotel ids are not deserializable to Vec").into_response(), + + }; - +/* let mut entries = Vec::new(); for r in rows { match r { @@ -615,27 +627,51 @@ pub async fn login_refresh_token ( Err(_) => continue, // ignore corrupt rows } } + */ - if entries.is_empty() { + if hotel_ids.is_empty() { return (StatusCode::UNAUTHORIZED, "No matching device").into_response(); } + if !verify_password(&payload.refresh_token, &saved_hash) { + // skip rows with wrong hash + return (StatusCode::UNAUTHORIZED, "Invelid credentials").into_response(); + } + + 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 mut tokens = Vec::new(); - //FIXME: swap to "for hotel_id in entries" // interator over vector list + for hotel_id in hotel_ids { + let claims = serde_json::json!({ + "id": user_id, + "hotel_id": hotel_id, + "exp": expiration + }); + + let token = match encode(&Header::default(), &claims, &keys.encoding) { + Ok(token) => token, + Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "JWT creation failed").into_response(), + }; + + tokens.push(token); + } + + /* OLD ITERATION OVER MULTIPLE REFRESH TOKEN + // 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, @@ -650,14 +686,15 @@ pub async fn login_refresh_token ( tokens.push(token); } + */ - -if tokens.is_empty() { - return (StatusCode::UNAUTHORIZED, "Invalid or mismatched token").into_response(); -} + if tokens.is_empty() { + return (StatusCode::UNAUTHORIZED, "Invalid or mismatched token").into_response(); + } //Json(tokens).into_response() Json(MultiLoginResponse { tokens }).into_response() + } pub async fn logout_from_single_device (