From 668173c40deb8015e05b44cd6eb304ddceb3b527 Mon Sep 17 00:00:00 2001 From: Romain Mallard Date: Thu, 4 Dec 2025 12:31:31 +0100 Subject: [PATCH] fix getting token through header cookies and not body --- Cargo.lock | 11 +++-- Cargo.toml | 1 + db/1.sqlite | Bin 4927488 -> 4927488 bytes db/1.sqlite-shm | Bin 32768 -> 0 bytes db/1.sqlite-wal | 0 db/auth_copy_2.sqlite | Bin 73728 -> 73728 bytes db/auth_copy_2.sqlite-shm | Bin 32768 -> 0 bytes db/auth_copy_2.sqlite-wal | Bin 12392 -> 0 bytes src/main.rs | 14 +++++- src/utils/auth.rs | 95 ++++++++++++++++---------------------- 10 files changed, 58 insertions(+), 63 deletions(-) delete mode 100644 db/1.sqlite-shm delete mode 100644 db/1.sqlite-wal delete mode 100644 db/auth_copy_2.sqlite-shm delete mode 100644 db/auth_copy_2.sqlite-wal diff --git a/Cargo.lock b/Cargo.lock index 8cbfea3..79369cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,7 +409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -672,6 +672,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "tower-http", "uuid", ] @@ -1469,7 +1470,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -1764,7 +1765,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -1922,9 +1923,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ "bitflags", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 7654ff2..07244a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ futures-util = {version = "0.3.31"} uuid = {version = "1.18.1", features = ["serde"] } base64 = "0.22.1" reqwest = { version = "0.12.24", features = ["json","blocking"] } +tower-http = { version = "0.6.7", features = ["cors"] } diff --git a/db/1.sqlite b/db/1.sqlite index 369beb4abd2739191460a23cd73cdef454eeedf8..0a33887d3616e35129ed699e6d1b36c882664918 100644 GIT binary patch delta 5578 zcmeI$UuauZ90%}obN}BY_at^*(k1m~-Do!|kA0l{j9OTKS5R{}HJ+@W+P}Lpb7sPxo|`>iET1h@PS4Fw z;EYk*Frq%;A^$n>b!6VZ)wX#Nzqy=mp{3ErdOP_KN}L}F26@<=sa-cGg&=M!()%*~ zg?>lxd(XM)-|!~y;7|7VTlumz>DL8`w1jPDkBry;u->)=gI~zKEcp2sxj1_B_qli? zOdk-Lo*?u*JwYGRD)oj|FR47)JJ)oncquPkv_zTcF{e^ITX7P0ilzFJww+A%C2Zz8 z{jQT~Co<6@n+4crm<{|r990k|&f^PN29>z!l*AQ_`DFNhkk#ubXFtP(8hp5FxZgFVi(Iy?W`@n?(QTfomzR^3vjm zpM=Ij%O6X7{N@ay8+4VH=_`~`YW`%do2%vr=8V^`ynfY;{pw=euMk}bJH?Ult(2BZ zvQ)y(xQw}W)-vkRh*O*{6$`VC0(QdAx@p_BGnW3S!0V^WmAC#~pwH5Ftl^mLSnAGI z*p{+G6-e5d1y+5JRR!>Y2olJkfC?JuV1OS25Cjt_gdhx0K@04HR@e;@h(a6eff&T0 z9i9dY60jFKU?1#ttNWvjF3=C{YfdgsigA8P$9|pjMK{x`>!gG*= z=V1t5fTM5>j>C&E3?uN;Emj@;n6xq)WnEZKW36hg!)dP L+z6v(k|g~F(jGG3 delta 5473 zcmeI$Z)h8390%~{E_au^rxzvq`+{`s1G8RmL29%D+t7)yW*ee=WKpvMk<-eu{6ncAvM`{-8cc4FNe zh%Xth85wO=|4CoAuBx+%g~glo@&3iz_3`{JKZsd%NZeCU^^?D6XUq_kT2*jpzFM9e(AtU1#ZH_aij6#rY&#iCv{HkMa{u`cnIJ}CZ7TC#FI$QYkW zTDO)vQcP8afY<@eV-S-f)vIW+Z5xT zKT`3%(d!qbv_&0ksVzn=`hr%Y?2fWK%I=+JcYeMe7p>U^Gu$WfkRTqIbAM1;CC+G_ zuF(vg#?XusD@v>=v9?dF`MUK9?|jBP637q(1ys-=4muc+fFzh;K?(@ckbymrg)ZoZ zCm;uTD8Q4@14VcWo`znqVK3~1{cr&K;2G$L0T_fKI0(Z~fwDlIemh91%~-JzAJ!bBA& zsxaGEm~DS6zlB}fG8L5>J*?fl)E=>&1XIyyZ@l7p4P*AGgLj+~uh@?3kGMXs=2e{Y zZzSyPA2s7+zE=tR0E00z_IOdxcD|lVr^7!%Ra%qjH~NL{(%MSeex*a ad`yk$v78=`xe{ZN79Q09!niy|QT_oWv?;a# diff --git a/db/1.sqlite-shm b/db/1.sqlite-shm deleted file mode 100644 index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeIuAr62r3I9!?e= zhJA(5EZKC$rV?s3n=V?3Wmi^pxaCEnpI`mq>PJ_$FMBJ${C7oOJ$?H8%H!3&OOf?su5oPbte<>)@Nrrm z50n;FYX(x#D^YOT_Skl-8ix^!p911M0J1LAsk74>jw^XQ&`{c=Azdrg4QS$*7`sA4 zC$ElfAFl!_A|Iv}&3U6UYh+V(*iNeqVbnYeo7Pf6gN|oFb}0BDsJ3&Y$MvcV!8dC~LBJ9j z86B8;6{sT49G3*XvrL^!56|e}OwnPPT#7W)aNtTlmI@MNHLhC-PfUh}KK3!V;p#f6 zk&PTx(xx*R1jUkXSVMo*o+^#TGIcKEXLNd)#`S2Nr7C5wT1FtGZxotzT-95iYxGCu z9N+2=NwLR{^VXaRa^-oaHEYzhl56=~9sr8fW$LVhXLO3?M9W3Wful7`f#Y+ar={xE zc*CLQT$Ao{Z=Km}OZ;L0DpEoUu%u3-L2LRmn}1 zBp(>%DHK#_7%$}eyb%{=rCUzHP%$$autuvZ%le21GH}}+$Vd*D2<0?5p9AKgxzz5Q zKRBaPs+GoW0h;s^P(|zxEl+?I)`%NehNqMUD*`;A8p`$tlCJ|Ltk|;{3NrlqkBt()Fjvy%2!Q1Z~vfcMMWh0T* zt%dEsL-vSqq)giywq<+R7OR1bWyflbjuXMSTA$aDx-Mk^nipIb>Z2{hWJJz^$zeap zyH&l}Yma10K?n^Y5hWS^G~pzQV@Q&OF(RodB&?{Y(k3B&NwViIza>k1o!Y2NlIVnT z)744>6caEXzB>ukIa+~PpD|l1k9P_xkeNUjR)8b|XdmC&zxYp?#3GkuQX(N#X#x}2 zNsHr(l31s3Bi>A@G&+#w9O`TKY))p=L6hZiX_zAw9iF@4EFT5k-dM{_Uw`iK)*|=Z ze3N??Un|Fgad({Kaq-7o~Fc6LHO+};j}-?$MHyna38y=&J(#<#XY9&B!g+}+p+xfPARKD)pFnm2Er J{`S)r|2LnGWw`(V delta 108 zcmV-y0F(cKzyyH61hDjP0S2@6ZwwF(0000354Zpik0S&X0tOGW(vLI{4A%e;UJktu91VF4*Rv52#SF9Bd`1BR9t4xXt|*gAes#0F Ou2vDV5|Hi>qR>$6Y$Hzq diff --git a/db/auth_copy_2.sqlite-shm b/db/auth_copy_2.sqlite-shm deleted file mode 100644 index 3564af8b6c553ad8d593abf46193863c8a81466c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI*y9ok85C&i$f#L(iKrS#i5X>yY+-j}@d$A4+xKJ>V3)DVzR^>1-G4%X?7-kuk zh5ZWH&CaVu!B z2oNAZfB*pk1PC-+pwsN@xg7xl1PFW(NWaer0RjXF5FkK+009C72oNAZfB*pk1PBly IK;S2!H?xfB*=900@8p2!H?xfB*>mj|HyAQ6l2@2X5ap?=Pm~zH@(J&tmVz z(GUOKj&DZL>yZau-}TVoKJSKidc7|=dGTbs^Xaq4;a(uNMI+d~%U@o;amnBMA^3m; z0w4eaAOHd&00JNY0w4eauLM>f#5a+RmE25R-@tWuICW^Nhac=x8QcyE%cXV}yY$X% zm%@9+F=v$}PBr)PozmT0)-Y$1f*U?H%-3_pT2a(%g26KSwC&W&T&9#z?lP*^RjQR% zWufs>iDG%(pvZ2LOB+U#Wq3NNb16Pa_DQ-+8%&SoGnV5`ZO76Hin_zzAwQ;e=ucL+ zVrL<@&kMQajoF^144o!XHyYf$JXQ)>1uvx%4&jtZUu~0&GcGoIuF>r$Ox|uucB^8l zrEx=Zi3C41f)H;SG7??gUO!8C<-CL*KT0n$W}ZA;9+4@tX%haVtl+ld%YsA~nMqex zb9y3QbZS!WkXU5cs$}IUVV?4xBXQ0(+80WQu5PZKMa0gFI2aswqRB3m0i)Gvx6U|y z$yRX16g#3OSi`oyJWMTHZfmq`c6@5G?@vaxNpOH=7`klCi-6k8qU6w zT?kaJ&>#7Nmd{qSWo{4eW9_)=F^vPPCm4}3u(g=+dj z0dGY&kw`cz*hci6VJR2(THVr^t=M8F-z+9PH;Am@shn&d$dt%9azoa Result<(), reqwest::Error> { let payload = serde_json::json!({ @@ -88,10 +92,16 @@ std::panic::set_hook(Box::new(|info| { }; + let cors = CorsLayer::new() + .allow_origin("http://localhost:5173".parse::().unwrap()) + .allow_credentials(true) + .allow_methods([Method::GET, Method::POST, Method::PUT , Method::OPTIONS]) + .allow_headers([CONTENT_TYPE, AUTHORIZATION]); let app = create_router(state) - .layer(Extension(jwt_keys)); - + .layer(Extension(jwt_keys)) + .layer(cors); + let listener = TcpListener::bind("0.0.0.0:7080").await?; serve(listener, app).into_future().await?; Ok(()) diff --git a/src/utils/auth.rs b/src/utils/auth.rs index cef5cba..4f73c27 100644 --- a/src/utils/auth.rs +++ b/src/utils/auth.rs @@ -6,14 +6,15 @@ use axum::{ use axum_extra::extract::TypedHeader; //use axum_extra::TypedHeader; -use headers::UserAgent; +use headers::{UserAgent, Cookie}; use axum::extract::FromRef; use axum::extract::Request as ExtractRequest; use jsonwebtoken::{decode, DecodingKey, Validation, encode, EncodingKey, Header, Algorithm}; +use reqwest::header::REFRESH; use serde::{Deserialize, Serialize}; use serde_json::Value; -use chrono::{Utc}; +use chrono::{Utc, format}; use rusqlite::{params, Connection, OptionalExtension}; use rand_core::{RngCore, OsRng}; @@ -468,16 +469,15 @@ pub async fn create_refresh_token( - //TODO: get hotel name + //TODO: get hotel name to return a map/tuple of hotel name 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 ? + //TODO: compiler les hotel id dans un vecteur pour le feed dans le refresh token let hotel_ids: Vec = match stmt .query_map(params![&user_id],|row| row.get (0)) { @@ -539,7 +539,9 @@ pub async fn create_refresh_token( */ - let cookie_value = format!("refresh_token={}; HttpOnly; Secure; Path=/", raw_token); + //TODO: add a map/tupple of of the allowed hotels and their id+name, maybe update the token ? + + let cookie_value = format!("refresh_token={}; HttpOnly; Secure; Max-Age=60480000000;Path=/", raw_token); let mut response = (StatusCode::CREATED, "Refresh token created successfully").into_response(); response.headers_mut().insert( @@ -553,7 +555,7 @@ pub async fn create_refresh_token( #[derive(Deserialize)] pub struct LoginRefreshTokenValues{ device_id: Uuid, - refresh_token: String, + //refresh_token: String, } //TODO: LATER : implement hotel-id-selected to allow user to only get part hotels ? @@ -561,29 +563,39 @@ pub async fn login_refresh_token ( State(state): State, Extension(keys): Extension, user_agent: Option>, + cookie_header: Option>, Json(payload): Json ) -> impl IntoResponse { + println!("login_refresh_token called"); + // Log cookies + + + let cookies = match cookie_header { + Some(token) => token, + None => return (StatusCode::UNAUTHORIZED, "Missing refresh token cookie").into_response(), + }; + + let refresh_token = match cookies.get("refresh_token") { + Some(token) => token.to_string(), + None => return (StatusCode::UNAUTHORIZED, "Missing refresh token cookie").into_response(), + }; + + println!("Cookies: {:?}", &refresh_token); + let conn = match state.logs_pool.get() { Ok(c) => c, Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB connection error").into_response(), }; - - /*let user_agent_str = user_agent - .map(|ua| ua.to_string()) - .unwrap_or_else(|| "Unknown".to_string()); - - 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(), }; - + println!("UA {:?}", &user_agent_str); let device_id_str = payload.device_id.to_string(); + println!("device id: {:?}", &device_id_str); //"SELECT user_id, token_hash, hotel_id FROM refresh_token WHERE device_id = ?1 AND user_agent = ?2", @@ -593,10 +605,11 @@ pub async fn login_refresh_token ( let mut stmt = match conn.prepare( "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 + LIMIT 1;" ) { Ok(s) => s, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), + Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "Error prepatring hotel_id_list stmt").into_response(), }; let rows = match stmt.query_one(params![&device_id_str, &user_agent_str], |row| { @@ -607,7 +620,10 @@ pub async fn login_refresh_token ( )) }) { Ok(r) => r, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "DB query error").into_response(), + Err(e) => { + eprintln!("DB ERROR: {:?}", e); + return (StatusCode::INTERNAL_SERVER_ERROR, format!("DB query error: {}", e)).into_response() + } }; //TODO: extraction of the blob //let json_hotel_ids = rows.2; @@ -619,21 +635,11 @@ pub async fn login_refresh_token ( }; -/* - let mut entries = Vec::new(); - for r in rows { - match r { - Ok(t) => entries.push(t), - Err(_) => continue, // ignore corrupt rows - } - } - */ - if hotel_ids.is_empty() { return (StatusCode::UNAUTHORIZED, "No matching device").into_response(); } - if !verify_password(&payload.refresh_token, &saved_hash) { + if !verify_password(&refresh_token, &saved_hash) { // skip rows with wrong hash return (StatusCode::UNAUTHORIZED, "Invelid credentials").into_response(); } @@ -663,31 +669,6 @@ pub async fn login_refresh_token ( 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 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(); } @@ -736,10 +717,12 @@ pub async fn logout_from_single_device ( None => return (StatusCode::UNAUTHORIZED, "No matching device").into_response(), }; + //FIXME: need to chang the way we get refresh token from the cookies instead + /* if !verify_password(&payload.refresh_token, &token_hash) { return (StatusCode::UNAUTHORIZED, "Invalid or mismatched token").into_response(); } - +*/ let revoked: Result = conn.query_row( "UPDATE refresh_token SET revoked = 1 WHERE id = ?1 RETURNING device_id", params![&token_id],