From f6cf5fc8747e22efe297fdb20172f5fc7cf15787 Mon Sep 17 00:00:00 2001 From: Chris Jean-Marie Date: Wed, 5 Oct 2022 20:41:22 -0400 Subject: [PATCH] Split oauth functions out of main --- Cargo.lock | 10 -- src/discord_oauth.rs | 122 ++++++++++++++++- src/facebook_oauth.rs | 122 +++++++++++++++++ src/google_oauth.rs | 130 +++++++++++++++++- src/main.rs | 311 ++---------------------------------------- 5 files changed, 380 insertions(+), 315 deletions(-) create mode 100644 src/facebook_oauth.rs diff --git a/Cargo.lock b/Cargo.lock index 88c9686..b822ae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,15 +503,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "envy" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" -dependencies = [ - "serde", -] - [[package]] name = "event-listener" version = "2.5.2" @@ -898,7 +889,6 @@ dependencies = [ "askama", "async-session", "axum", - "envy", "headers", "http", "oauth2", diff --git a/src/discord_oauth.rs b/src/discord_oauth.rs index 6cc4fb8..d8945d8 100644 --- a/src/discord_oauth.rs +++ b/src/discord_oauth.rs @@ -1,9 +1,123 @@ -async fn discord_auth(Extension(client): Extension) -> impl IntoResponse { - let (auth_url, _csrf_token) = client +use async_session::{MemoryStore, Session, SessionStore as _}; +use axum::{ + async_trait, + extract::{ + rejection::TypedHeaderRejectionReason, Extension, FromRequest, Query, RequestParts, + TypedHeader, + }, + headers::Cookie, + http::{ + self, + header::SET_COOKIE, + header::{HeaderMap, HeaderValue}, + StatusCode + }, + response::{Html, IntoResponse, Redirect, Response}, + routing::{get, get_service}, + Router, body::{BoxBody, boxed}, +}; +use http::{header}; +use oauth2::{ + basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, + PkceCodeChallenge, RedirectUrl, Scope, TokenUrl, + ClientSecret, TokenResponse, CsrfToken, +}; +use serde::{Deserialize, Serialize}; +use std::{env, net::SocketAddr, collections::HashMap}; +use tower_http::services::ServeDir; +use uuid::Uuid; + +use crate::User; +use crate::COOKIE_NAME; + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct AuthRequest { + code: String, + state: String, +} + +pub async fn discord_auth() -> impl IntoResponse { + let discord_oauth_client = discord_oauth_client(); + let (auth_url, _csrf_token) = discord_oauth_client .authorize_url(CsrfToken::new_random) .add_scope(Scope::new("identify".to_string())) .url(); // Redirect to Discord's oauth service - Redirect::to(auth_url.to_string().parse().unwrap()) -} \ No newline at end of file + Redirect::to(&auth_url.to_string()) +} + +pub async fn discord_authorized( + Query(query): Query, + Extension(store): Extension, + Extension(oauth_clients): Extension>, +) -> impl IntoResponse { + // Check for Discord client + if oauth_clients.contains_key("Discord") { + // Get Discord client + let discord_oauth_client = oauth_clients.get(&"Discord").unwrap(); + + // Get an auth token + let token = discord_oauth_client + .exchange_code(AuthorizationCode::new(query.code.clone())) + .request_async(async_http_client) + .await + .unwrap(); + + // Fetch user data from discord + let client = reqwest::Client::new(); + let user_data: User = client + // https://discord.com/developers/docs/resources/user#get-current-user + .get("https://discordapp.com/api/users/@me") + .bearer_auth(token.access_token().secret()) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + + // Create a new session filled with user data + let mut session = Session::new(); + session.insert("user", &user_data).unwrap(); + + // Store session and get corresponding cookie + let cookie = store.store_session(session).await.unwrap().unwrap(); + + // Build the cookie + let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); + + // Set cookie + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, cookie.parse().unwrap()); + + (headers, Redirect::to(&"/dashboard")) + } else { + let headers = HeaderMap::new(); + + (headers, Redirect::to(&"/")) + } +} + +pub fn discord_oauth_client() -> BasicClient { + let redirect_url = env::var("REDIRECT_URL") + //.unwrap_or_else(|_| "http://localhost:40192/auth/discord".to_string()); + .unwrap_or_else(|_| "https://www.jean-marie.ca/auth/discord".to_string()); + + let discord_client_id = env::var("DISCORD_CLIENT_ID").expect("Missing DISCORD_CLIENT_ID!"); + let discord_client_secret = env::var("DISCORD_CLIENT_SECRET").expect("Missing DISCORD_CLIENT_SECRET!"); + let discord_auth_url = env::var("DISCORD_AUTH_URL").unwrap_or_else(|_| { + "https://discord.com/api/oauth2/authorize?response_type=code".to_string() + }); + let discord_token_url = env::var("DISCORD_TOKEN_URL") + .unwrap_or_else(|_| "https://discord.com/api/oauth2/token".to_string()); + + BasicClient::new( + ClientId::new(discord_client_id), + Some(ClientSecret::new(discord_client_secret)), + AuthUrl::new(discord_auth_url).unwrap(), + Some(TokenUrl::new(discord_token_url).unwrap()), + ) + .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) +} diff --git a/src/facebook_oauth.rs b/src/facebook_oauth.rs new file mode 100644 index 0000000..36f86dd --- /dev/null +++ b/src/facebook_oauth.rs @@ -0,0 +1,122 @@ +use async_session::{MemoryStore, Session, SessionStore as _}; +use axum::{ + async_trait, + extract::{ + rejection::TypedHeaderRejectionReason, Extension, FromRequest, Query, RequestParts, + TypedHeader, + }, + headers::Cookie, + http::{ + self, + header::SET_COOKIE, + header::{HeaderMap, HeaderValue}, + StatusCode + }, + response::{Html, IntoResponse, Redirect, Response}, + routing::{get, get_service}, + Router, body::{BoxBody, boxed}, +}; +use http::{header}; +use oauth2::{ + basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, + PkceCodeChallenge, RedirectUrl, Scope, TokenUrl, + ClientSecret, TokenResponse, CsrfToken, +}; +use serde::{Deserialize, Serialize}; +use std::{env, net::SocketAddr, collections::HashMap}; +use tower_http::services::ServeDir; +use uuid::Uuid; + +use crate::User; +use crate::COOKIE_NAME; + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct AuthRequest { + code: String, + state: String, +} + +pub async fn facebook_auth() -> impl IntoResponse { + let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256(); + + // Generate the authorization URL to which we'll redirect the user. + let (auth_url, csrf_state) = facebook_oauth_client() + .authorize_url(CsrfToken::new_random) + .set_pkce_challenge(pkce_code_challenge) + .url(); + + // Redirect to Facebook's oauth service + Redirect::to(&auth_url.to_string()) +} + +pub fn facebook_oauth_client() -> BasicClient { + let redirect_url = env::var("REDIRECT_URL") + .unwrap_or_else(|_| "http://localhost:40192/auth/facebook".to_string()); + //.unwrap_or_else(|_| "https://www.jean-marie.ca/auth/facebook".to_string()); + + let facebook_client_id = env::var("FACEBOOK_CLIENT_ID").expect("Missing FACEBOOK_CLIENT_ID!"); + let facebook_client_secret = env::var("FACEBOOK_CLIENT_SECRET").expect("Missing FACEBOOK_CLIENT_SECRET!"); + let facebook_auth_url = env::var("FACEBOOK_AUTH_URL").unwrap_or_else(|_| { + "https://www.facebook.com/v15.0/dialog/oauth".to_string() + }); + let facebook_token_url = env::var("FACEBOOK_TOKEN_URL") + .unwrap_or_else(|_| "https://graph.facebook.com/v15.0/oauth/access_token".to_string()); + + BasicClient::new( + ClientId::new(facebook_client_id), + Some(ClientSecret::new(facebook_client_secret)), + AuthUrl::new(facebook_auth_url).unwrap(), + Some(TokenUrl::new(facebook_token_url).unwrap()), + ) + .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) +} + +pub async fn facebook_authorized( + Query(query): Query, + Extension(store): Extension, + Extension(oauth_clients): Extension>, +) -> impl IntoResponse { + // Check for Facebook client + if oauth_clients.contains_key("Facebook") { + // Get Facebook client + let oauth_client = oauth_clients.get(&"Facebook").unwrap(); + + // Get an auth token + let token = oauth_client + .exchange_code(AuthorizationCode::new(query.code.clone())) + .request_async(async_http_client) + .await + .unwrap(); + + // Fetch user data from facebook + let client = reqwest::Client::new(); + let user_data: = client + .get("https://graph.facebook.com/v15.0/dialog/oauth") + .bearer_auth(token.access_token().secret()) + .send() + .await + .unwrap(); + + // // Create a new session filled with user data + // let mut session = Session::new(); + // session.insert("user", &user_data).unwrap(); + + // // Store session and get corresponding cookie + // let cookie = store.store_session(session).await.unwrap().unwrap(); + + // // Build the cookie + // let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); + + // // Set cookie + let mut headers = HeaderMap::new(); + // headers.insert(SET_COOKIE, cookie.parse().unwrap()); + + (headers, Redirect::to(&"/dashboard")) + } else { + let mut headers = HeaderMap::new(); + + (headers, Redirect::to(&"/")) + } +} + diff --git a/src/google_oauth.rs b/src/google_oauth.rs index 0eb8bb5..10695dd 100644 --- a/src/google_oauth.rs +++ b/src/google_oauth.rs @@ -1,9 +1,129 @@ -async fn google_auth(Extension(client): Extension) -> impl IntoResponse { - let (auth_url, _csrf_token) = client +use async_session::{MemoryStore, Session, SessionStore as _}; +use axum::{ + extract::{ + Extension, Query, + }, + http::{ + self, + header::{SET_COOKIE, HeaderMap} + }, + response::{IntoResponse, Redirect}, +}; +use http::{header}; +use oauth2::{ + basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, + PkceCodeChallenge, RedirectUrl, Scope, TokenUrl, + ClientSecret, TokenResponse, CsrfToken, +}; +use serde::{Deserialize, Serialize}; +use std::{env, net::SocketAddr, collections::HashMap}; + +use crate::User; +use crate::COOKIE_NAME; + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct AuthRequest { + code: String, + state: String, +} + +pub async fn google_auth() -> impl IntoResponse { + let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256(); + + // Generate the authorization URL to which we'll redirect the user. + let (auth_url, csrf_state) = google_oauth_client() .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new("identify".to_string())) + .add_scope(Scope::new( + "https://www.googleapis.com/auth/userinfo.profile".to_string(), + )) + .add_scope(Scope::new( + "https://www.googleapis.com/auth/userinfo.email".to_string(), + )) + .set_pkce_challenge(pkce_code_challenge) .url(); // Redirect to Google's oauth service - Redirect::to(auth_url.to_string().parse().unwrap()) -} \ No newline at end of file + Redirect::to(&auth_url.to_string()) +} + +pub fn google_oauth_client() -> BasicClient { + let redirect_url = env::var("REDIRECT_URL") + //.unwrap_or_else(|_| "http://localhost:40192/auth/callback".to_string()); + .unwrap_or_else(|_| "https://www.jean-marie.ca/auth/google".to_string()); + + let google_client_id = env::var("GOOGLE_CLIENT_ID").expect("Missing GOOGLE_CLIENT_ID!"); + let google_client_secret = env::var("GOOGLE_CLIENT_SECRET").expect("Missing GOOGLE_CLIENT_SECRET!"); + let google_auth_url = env::var("GOOGLE_AUTH_URL").unwrap_or_else(|_| { + "https://accounts.google.com/o/oauth2/v2/auth".to_string() + }); + let google_token_url = env::var("GOOGLE_TOKEN_URL") + .unwrap_or_else(|_| "https://www.googleapis.com/oauth2/v3/token".to_string()); + + BasicClient::new( + ClientId::new(google_client_id), + Some(ClientSecret::new(google_client_secret)), + AuthUrl::new(google_auth_url).unwrap(), + Some(TokenUrl::new(google_token_url).unwrap()), + ) + .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) +} + +pub async fn google_authorized( + Query(query): Query, + Extension(store): Extension, + Extension(oauth_clients): Extension>, +) -> impl IntoResponse { + // Check for Google client + if oauth_clients.contains_key("Google") { + // Get Google client + let oauth_client = oauth_clients.get(&"Google").unwrap(); +/* + // Get an auth token + let token = google_oauth_client + .exchange_code(AuthorizationCode::new(query.code.clone())) + .request_async(async_http_client) + .await + .unwrap(); + + // Fetch user data from google + let client = reqwest::Client::new(); + let user_data: User = client + // https://discord.com/developers/docs/resources/user#get-current-user + .get("https://discordapp.com/api/users/@me") + .bearer_auth(token.access_token().secret()) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); +*/ + + // Create a new session filled with user data + let session = Session::new(); + //session.insert("user", &user_data).unwrap(); + + // Store session and get corresponding cookie + let cookie = store.store_session(session).await.unwrap().unwrap(); + + // Build the cookie + let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); + + // Set cookie + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, cookie.parse().unwrap()); + + //(headers, Redirect::to("/dashboard".parse().unwrap())) + } + + let mut page = String::new(); + page.push_str(&"Display the data returned by Google\n".to_string()); + page.push_str(&"\nState: ".to_string()); + page.push_str(&query.state); + page.push_str(&"\nCode: ".to_string()); + page.push_str(&query.code); + page.push_str(&"\nScope: ".to_string()); + + page +} diff --git a/src/main.rs b/src/main.rs index ef2adea..29e0544 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,31 +3,36 @@ use async_session::{MemoryStore, Session, SessionStore as _}; use axum::{ async_trait, extract::{ - rejection::TypedHeaderRejectionReason, Extension, FromRequest, Query, RequestParts, + rejection::TypedHeaderRejectionReason, Extension, FromRequest, RequestParts, TypedHeader, }, headers::Cookie, http::{ self, - header::SET_COOKIE, - header::{HeaderMap, HeaderValue}, + header::{HeaderValue}, StatusCode }, response::{Html, IntoResponse, Redirect, Response}, routing::{get, get_service}, - Router, body::{BoxBody, boxed}, + Router, }; use http::{header}; use oauth2::{ - basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, - PkceCodeChallenge, RedirectUrl, Scope, TokenUrl, - ClientSecret, TokenResponse, CsrfToken, + basic::BasicClient, }; use serde::{Deserialize, Serialize}; -use std::{env, net::SocketAddr, collections::HashMap}; +use std::{net::SocketAddr, collections::HashMap}; use tower_http::services::ServeDir; use uuid::Uuid; +mod google_oauth; +mod facebook_oauth; +mod discord_oauth; + +use google_oauth::*; +use facebook_oauth::*; +use discord_oauth::*; + const COOKIE_NAME: &str = "SESSION"; // The user data we'll get back from Discord. @@ -80,7 +85,6 @@ async fn main() { let google_oauth_client = google_oauth_client(); // Get oauth clients for the hashmap - //oauth_clients.insert("Google".to_string(), google_oauth_client); oauth_clients.insert("Facebook", facebook_oauth_client); oauth_clients.insert("Discord", discord_oauth_client); oauth_clients.insert("Google", google_oauth_client); @@ -104,10 +108,10 @@ async fn main() { .route("/logout", get(logout)) .route("/dashboard", get(dashboard)) .route("/google_auth", get(google_auth)) - .route("/facebook_auth", get(facebook_auth)) - .route("/discord_auth", get(discord_auth)) .route("/auth/google", get(google_authorized)) + .route("/facebook_auth", get(facebook_auth)) .route("/auth/facebook", get(facebook_authorized)) + .route("/discord_auth", get(discord_auth)) .route("/auth/discord", get(discord_authorized)) .layer(Extension(store)) .layer(Extension(oauth_clients)); @@ -147,72 +151,6 @@ async fn dashboard(user: User) -> impl IntoResponse { HtmlTemplate(template) } -fn google_oauth_client() -> BasicClient { - let redirect_url = env::var("REDIRECT_URL") - //.unwrap_or_else(|_| "http://localhost:40192/auth/callback".to_string()); - .unwrap_or_else(|_| "https://www.jean-marie.ca/auth/google".to_string()); - - let google_client_id = env::var("GOOGLE_CLIENT_ID").expect("Missing GOOGLE_CLIENT_ID!"); - let google_client_secret = env::var("GOOGLE_CLIENT_SECRET").expect("Missing GOOGLE_CLIENT_SECRET!"); - let google_auth_url = env::var("GOOGLE_AUTH_URL").unwrap_or_else(|_| { - "https://accounts.google.com/o/oauth2/v2/auth".to_string() - }); - let google_token_url = env::var("GOOGLE_TOKEN_URL") - .unwrap_or_else(|_| "https://www.googleapis.com/oauth2/v3/token".to_string()); - - BasicClient::new( - ClientId::new(google_client_id), - Some(ClientSecret::new(google_client_secret)), - AuthUrl::new(google_auth_url).unwrap(), - Some(TokenUrl::new(google_token_url).unwrap()), - ) - .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) -} - -fn facebook_oauth_client() -> BasicClient { - let redirect_url = env::var("REDIRECT_URL") - //.unwrap_or_else(|_| "http://localhost:40192/auth/facebook".to_string()); - .unwrap_or_else(|_| "https://www.jean-marie.ca/auth/facebook".to_string()); - - let facebook_client_id = env::var("FACEBOOK_CLIENT_ID").expect("Missing FACEBOOK_CLIENT_ID!"); - let facebook_client_secret = env::var("FACEBOOK_CLIENT_SECRET").expect("Missing FACEBOOK_CLIENT_SECRET!"); - let facebook_auth_url = env::var("FACEBOOK_AUTH_URL").unwrap_or_else(|_| { - "https://www.facebook.com/v11.0/dialog/oauth".to_string() - }); - let facebook_token_url = env::var("FACEBOOK_TOKEN_URL") - .unwrap_or_else(|_| "https://graph.facebook.com/v11.0/oauth/access_token".to_string()); - - BasicClient::new( - ClientId::new(facebook_client_id), - Some(ClientSecret::new(facebook_client_secret)), - AuthUrl::new(facebook_auth_url).unwrap(), - Some(TokenUrl::new(facebook_token_url).unwrap()), - ) - .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) -} - -fn discord_oauth_client() -> BasicClient { - let redirect_url = env::var("REDIRECT_URL") - //.unwrap_or_else(|_| "http://localhost:40192/auth/discord".to_string()); - .unwrap_or_else(|_| "https://www.jean-marie.ca/auth/discord".to_string()); - - let discord_client_id = env::var("DISCORD_CLIENT_ID").expect("Missing DISCORD_CLIENT_ID!"); - let discord_client_secret = env::var("DISCORD_CLIENT_SECRET").expect("Missing DISCORD_CLIENT_SECRET!"); - let discord_auth_url = env::var("DISCORD_AUTH_URL").unwrap_or_else(|_| { - "https://discord.com/api/oauth2/authorize?response_type=code".to_string() - }); - let discord_token_url = env::var("DISCORD_TOKEN_URL") - .unwrap_or_else(|_| "https://discord.com/api/oauth2/token".to_string()); - - BasicClient::new( - ClientId::new(discord_client_id), - Some(ClientSecret::new(discord_client_secret)), - AuthUrl::new(discord_auth_url).unwrap(), - Some(TokenUrl::new(discord_token_url).unwrap()), - ) - .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()) -} - #[derive(Template)] #[template(path = "login.html")] struct LoginTemplate { @@ -354,225 +292,6 @@ async fn logout( Redirect::to(&"/") } -async fn google_auth() -> impl IntoResponse { - let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256(); - - // Generate the authorization URL to which we'll redirect the user. - let (auth_url, csrf_state) = google_oauth_client() - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new( - "https://www.googleapis.com/auth/userinfo.profile".to_string(), - )) - .add_scope(Scope::new( - "https://www.googleapis.com/auth/userinfo.email".to_string(), - )) - .set_pkce_challenge(pkce_code_challenge) - .url(); - - // Redirect to Google's oauth service - Redirect::to(&auth_url.to_string()) -} - -async fn facebook_auth() -> impl IntoResponse { - let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256(); - - // Generate the authorization URL to which we'll redirect the user. - let (auth_url, csrf_state) = facebook_oauth_client() - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new( - "https://www.googleapis.com/auth/userinfo.profile".to_string(), - )) - .add_scope(Scope::new( - "https://www.googleapis.com/auth/userinfo.email".to_string(), - )) - .set_pkce_challenge(pkce_code_challenge) - .url(); - - // Redirect to Google's oauth service - Redirect::to(&auth_url.to_string()) -} - -async fn discord_auth() -> impl IntoResponse { - let discord_oauth_client = discord_oauth_client(); - let (auth_url, _csrf_token) = discord_oauth_client - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new("identify".to_string())) - .url(); - - // Redirect to Discord's oauth service - Redirect::to(&auth_url.to_string()) -} - -#[derive(Debug, Deserialize)] -#[allow(dead_code)] -struct AuthRequest { - code: String, - state: String, -} - -async fn google_authorized( - Query(query): Query, - Extension(store): Extension, - Extension(oauth_clients): Extension>, -) -> impl IntoResponse { - // Check for Google client - if oauth_clients.contains_key("Google") { - // Get Google client - let oauth_client = oauth_clients.get(&"Google").unwrap(); -/* - // Get an auth token - let token = google_oauth_client - .exchange_code(AuthorizationCode::new(query.code.clone())) - .request_async(async_http_client) - .await - .unwrap(); - - // Fetch user data from discord - let client = reqwest::Client::new(); - let user_data: User = client - // https://discord.com/developers/docs/resources/user#get-current-user - .get("https://discordapp.com/api/users/@me") - .bearer_auth(token.access_token().secret()) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); -*/ - - // Create a new session filled with user data - let session = Session::new(); - //session.insert("user", &user_data).unwrap(); - - // Store session and get corresponding cookie - let cookie = store.store_session(session).await.unwrap().unwrap(); - - // Build the cookie - let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); - - // Set cookie - let mut headers = HeaderMap::new(); - headers.insert(SET_COOKIE, cookie.parse().unwrap()); - - //(headers, Redirect::to("/dashboard".parse().unwrap())) - } - - let mut page = String::new(); - page.push_str(&"Display the data returned by Google\n".to_string()); - page.push_str(&"\nState: ".to_string()); - page.push_str(&query.state); - page.push_str(&"\nCode: ".to_string()); - page.push_str(&query.code); - page.push_str(&"\nScope: ".to_string()); - - page -} - -async fn facebook_authorized( - Query(query): Query, - Extension(store): Extension, - Extension(oauth_clients): Extension>, -) -> impl IntoResponse { - // Check for Facebook client - if oauth_clients.contains_key("Facebook") { - // Get Facebook client - let oauth_client = oauth_clients.get(&"Facebook").unwrap(); - - // Get an auth token - let token = oauth_client - .exchange_code(AuthorizationCode::new(query.code.clone())) - .request_async(async_http_client) - .await - .unwrap(); - - // Fetch user data from discord - let client = reqwest::Client::new(); - let user_data: User = client - // https://discord.com/developers/docs/resources/user#get-current-user - .get("https://discordapp.com/api/users/@me") //TODO - replace with Facebook info url - .bearer_auth(token.access_token().secret()) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); - - // Create a new session filled with user data - let mut session = Session::new(); - session.insert("user", &user_data).unwrap(); - - // Store session and get corresponding cookie - let cookie = store.store_session(session).await.unwrap().unwrap(); - - // Build the cookie - let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); - - // Set cookie - let mut headers = HeaderMap::new(); - headers.insert(SET_COOKIE, cookie.parse().unwrap()); - - (headers, Redirect::to(&"/dashboard")) - } else { - let mut headers = HeaderMap::new(); - - (headers, Redirect::to(&"/")) - } -} - -async fn discord_authorized( - Query(query): Query, - Extension(store): Extension, - Extension(oauth_clients): Extension>, -) -> impl IntoResponse { - // Check for Discord client - if oauth_clients.contains_key("Discord") { - // Get Discord client - let discord_oauth_client = oauth_clients.get(&"Discord").unwrap(); - - // Get an auth token - let token = discord_oauth_client - .exchange_code(AuthorizationCode::new(query.code.clone())) - .request_async(async_http_client) - .await - .unwrap(); - - // Fetch user data from discord - let client = reqwest::Client::new(); - let user_data: User = client - // https://discord.com/developers/docs/resources/user#get-current-user - .get("https://discordapp.com/api/users/@me") - .bearer_auth(token.access_token().secret()) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); - - // Create a new session filled with user data - let mut session = Session::new(); - session.insert("user", &user_data).unwrap(); - - // Store session and get corresponding cookie - let cookie = store.store_session(session).await.unwrap().unwrap(); - - // Build the cookie - let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); - - // Set cookie - let mut headers = HeaderMap::new(); - headers.insert(SET_COOKIE, cookie.parse().unwrap()); - - (headers, Redirect::to(&"/dashboard")) - } else { - let headers = HeaderMap::new(); - - (headers, Redirect::to(&"/")) - } -} - struct AuthRedirect; impl IntoResponse for AuthRedirect {