From e198fb0ce00381547993970a08e80b3eb4dbfacd Mon Sep 17 00:00:00 2001 From: maix0 Date: Mon, 30 Sep 2024 17:36:45 +0200 Subject: [PATCH] update: should fix the token getting too old --- src/main.rs | 12 ++++++--- src/oauth2.rs | 72 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/main.rs b/src/main.rs index a2c30b7..f5d66f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ async fn tutors(config: AppState) { .oauth .do_request::>( "https://api.intra.42.fr/v2/groups/166/users", - &json! ({ + json! ({ "page[number]": page_nb, "page[size]": 100, }), @@ -120,7 +120,7 @@ async fn main() { http.clone(), unwrap_env!("CLIENT_ID"), unwrap_env!("CLIENT_SECRET"), - "https://t.maix.me/auth/callback", + "http://local.maix.me:9911/auth/callback", ) .await .unwrap(); @@ -198,13 +198,17 @@ async fn oauth2_callback( let res: User42 = state .oauth - .do_request("https://api.intra.42.fr/v2/me", &(), Some(&token)) + .do_request( + "https://api.intra.42.fr/v2/me", + &[] as &[(String, String); 0], + Some(&token), + ) .await .wrap_err("Unable to get user self")?; let mut cookie = Cookie::new("token", res.id.to_string()); cookie.set_same_site(SameSite::None); - cookie.set_secure(true); + cookie.set_secure(false); cookie.set_path("/"); // cookie.set_domain("localhost:3000"); // cookie.set_http_only(Some(false)); diff --git a/src/oauth2.rs b/src/oauth2.rs index 816a85f..0c172bb 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -3,13 +3,20 @@ use std::collections::HashMap; use base64::Engine; use color_eyre::eyre::{self, WrapErr}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use tracing::info; + +#[derive(Clone, Serialize, Deserialize)] +struct ApiError<'a> { + message: &'a str, + error: &'a str, +} #[derive(Clone, Debug)] pub struct OauthClient { client_id: String, client_secret: String, redirect_uri: String, - token: Token, + token: std::sync::Arc>, http: reqwest::Client, } @@ -71,7 +78,7 @@ impl OauthClient { Ok(Self { client_id: uid.to_string(), client_secret: secret.to_string(), - token, + token: std::sync::Arc::new(tokio::sync::Mutex::new(token)), redirect_uri, http: client, }) @@ -125,24 +132,49 @@ impl OauthClient { pub async fn do_request( &self, url: impl AsRef, - qs: &impl Serialize, - token: Option<&impl IntoToken>, + qs: impl Serialize, + token: Option<&Token>, ) -> eyre::Result { - let url = url.as_ref(); - let token = token - .map(IntoToken::get_token) - .unwrap_or_else(|| self.token.get_token()); - let res = self - .http - .get(url) - .query(qs) - .bearer_auth(token) - .send() - .await - .wrap_err("Failed to send request")?; - let text = res.text().await.wrap_err("API reponse to text")?; - let json = serde_json::from_str(&text) - .wrap_err_with(|| format!("API response to json: {text}"))?; - Ok(json) + loop { + let url = url.as_ref(); + let is_apptoken = token.is_none(); + let s: String; + let token = match token { + Some(i) => i.get_token(), + None => { + s = self.token.lock().await.get_token().to_string(); + s.as_str() + } + }; + let res = self + .http + .get(url) + .query(&qs) + .bearer_auth(token) + .send() + .await + .wrap_err("Failed to send request")?; + let text = res.text().await.wrap_err("API reponse to text")?; + if let Ok(err) = serde_json::from_str::>(&text) { + if is_apptoken + && err.message == "The access token expired" + && err.error == "Not authorized" + { + info!("Refreshing token !"); + + let tok = Self::get_app_token( + self.http.clone(), + &self.client_id, + &self.client_secret, + ) + .await?; + *self.token.lock().await = tok; + continue; + } + } + let json = serde_json::from_str(&text) + .wrap_err_with(|| format!("API response to json: {text}"))?; + break Ok(json); + } } }