diff --git a/Cargo.lock b/Cargo.lock index 167306e..c45b9ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,9 +77,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -1330,9 +1330,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.78" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9b4733a9c8b8aaa20634df36eeb68cc0c0669f2e18fb287006b496a14195d" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", diff --git a/src/main.rs b/src/main.rs index fba5e96..698af93 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use std::{ collections::{HashMap, HashSet}, - sync::{Arc, RwLock}, + sync::Arc, time::Duration, }; @@ -14,21 +14,21 @@ use axum::{ async_trait, extract::{FromRef, FromRequestParts, Query, State}, http::{request::Parts, StatusCode}, - response::{AppendHeaders, Html, IntoResponse, Redirect}, + response::{Html, IntoResponse, Redirect}, routing::get, - Json, Router, + Router, }; use axum_extra::extract::{ - cookie::{Cookie, Expiration, Key, SameSite}, + cookie::{Cookie, Key, SameSite}, CookieJar, PrivateCookieJar, }; use base64::Engine; use color_eyre::eyre::Context; use reqwest::tls::Version; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::{json, Value}; -use tokio::{io::AsyncReadExt, sync::Mutex}; -use tracing::{error, info}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tokio::sync::Mutex; +use tracing::{error, info, warn}; macro_rules! unwrap_env { ($name:literal) => { @@ -78,6 +78,7 @@ async fn tutors(config: AppState) { "page[number]": page_nb, "page[size]": 100, }), + Option::<&oauth2::Token>::None, ) .await .unwrap(); @@ -119,7 +120,7 @@ async fn main() { http.clone(), unwrap_env!("CLIENT_ID"), unwrap_env!("CLIENT_SECRET"), - "http://local.maix.me/auth/callback", + "http://local.maix.me:9911/auth/callback", ) .await .unwrap(); @@ -147,7 +148,7 @@ async fn main() { // run our app with hyper let listener = tokio::net::TcpListener::bind(format!( - "127.0.0.1:{}", + "0.0.0.0:{}", std::env::args() .nth(1) .and_then(|s| s.parse::().ok()) @@ -175,9 +176,6 @@ async fn oauth2_login(State(state): State) -> Result, @@ -197,18 +195,15 @@ async fn oauth2_callback( .await .wrap_err("callback")?; - let rep = state - .http - .get("https://api.intra.42.fr/v2/users/me") - .bearer_auth(&token.access_token) - .send() + let res: User42 = state + .oauth + .do_request("https://api.intra.42.fr/v2/me", &(), Some(&token)) .await .wrap_err("Unable to get user self")?; - let json: User42 = rep.json().await.wrap_err("unable to parse api reply")?; - let mut cookie = Cookie::new("token", json.id.to_string()); + 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)); @@ -225,23 +220,20 @@ async fn oauth2_callback( } #[derive(Clone, Debug)] -struct UserLoggedIn { - id: u64, -} +struct UserLoggedIn; #[async_trait] impl FromRequestParts for UserLoggedIn { - type Rejection = (StatusCode, CookieJar, Redirect); + type Rejection = (StatusCode, PrivateCookieJar, Redirect); async fn from_request_parts( parts: &mut Parts, state: &AppState, ) -> Result { - info!("banane"); - let jar = CookieJar::from_request_parts(parts, state).await.unwrap(); - dbg!(&jar); + let jar = PrivateCookieJar::from_request_parts(parts, state) + .await + .unwrap(); let Some(id) = jar.get("token") else { - info!("no cookie"); return Err(( StatusCode::TEMPORARY_REDIRECT, jar, @@ -251,7 +243,6 @@ impl FromRequestParts for UserLoggedIn { let Ok(user_id) = id.value().parse::() else { let jar = jar.remove("token"); - info!("not id"); return Err(( StatusCode::TEMPORARY_REDIRECT, jar, @@ -260,10 +251,8 @@ impl FromRequestParts for UserLoggedIn { }; if state.tutors.lock().await.contains(&user_id) { - info!("is tut"); - Ok(UserLoggedIn { id: user_id }) + Ok(UserLoggedIn) } else { - info!("not tut"); let jar = jar.remove("token"); Err(( StatusCode::TEMPORARY_REDIRECT, @@ -283,9 +272,8 @@ async fn root(_user: UserLoggedIn) -> Html<&'static str> { stop
start
status
- db
git pull (ask before!)
- "#, + "#, ) } diff --git a/src/oauth2.rs b/src/oauth2.rs index 832815d..10c0182 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -17,13 +17,23 @@ pub struct OauthClient { pub struct Token { #[serde(default)] refresh_token: Option, - pub access_token: String, + access_token: String, token_type: String, expires_in: u64, scope: String, created_at: u64, } +pub trait IntoToken { + fn get_token(&self) -> &str; +} + +impl IntoToken for Token { + fn get_token(&self) -> &str { + &self.access_token + } +} + impl OauthClient { async fn get_app_token( client: reqwest::Client, @@ -43,10 +53,7 @@ impl OauthClient { .send() .await .wrap_err("Sending request to fetch 42 API token")?; - let body = response.bytes().await?; - let text = String::from_utf8_lossy(&body); - println!("{}", text); - let json: Token = serde_json::from_slice(&body).unwrap(); // response.json().await.wrap_err("API response to json")?; + let json: Token = response.json().await.wrap_err("API response to json")?; Ok(json) } pub async fn new( @@ -77,7 +84,7 @@ impl OauthClient { .scheme("https") .authority("api.intra.42.fr") .path_and_query(format!( - "/oauth/authorize?client_id={}&scope=public&response_type=code&redirect_uri={redirect_uri}&code={}", + "/oauth/authorize?client_id={}&scope=public&response_type=code&redirect_uri={redirect_uri}&state={}", self.client_id, base64::engine::general_purpose::URL_SAFE.encode(csrf) )) .build() @@ -115,13 +122,17 @@ impl OauthClient { &self, url: impl AsRef, qs: &impl Serialize, + token: Option<&impl IntoToken>, ) -> eyre::Result { let url = url.as_ref(); + let token = token + .map(IntoToken::get_token) + .unwrap_or_else(|| self.token.get_token()); let req = self .http .get(url) .query(qs) - .bearer_auth(&self.token.access_token) + .bearer_auth(token) .send() .await .wrap_err("Failed to send request")?;