diff options
Diffstat (limited to 'crates/api-auth/src/discord')
| -rw-r--r-- | crates/api-auth/src/discord/mod.rs | 101 |
1 files changed, 24 insertions, 77 deletions
diff --git a/crates/api-auth/src/discord/mod.rs b/crates/api-auth/src/discord/mod.rs index 0844f58..43a62bf 100644 --- a/crates/api-auth/src/discord/mod.rs +++ b/crates/api-auth/src/discord/mod.rs @@ -1,7 +1,7 @@ use api_core::models::user::User; use async_session::{Session, serde_json}; use async_trait::async_trait; -use oauth2::{AuthorizationCode, CsrfToken, Scope, TokenResponse}; +use oauth2::{AuthorizationCode, CsrfToken, TokenResponse}; use redis::AsyncCommands; use serde::{Deserialize, Serialize}; use sh_util::cache::{CacheKey, RedisManager}; @@ -19,11 +19,19 @@ struct DiscordUser { avatar: Option<String>, username: String, discriminator: String, + email: Option<String>, + verified: bool, } -impl From<DiscordUser> for User { - fn from(value: DiscordUser) -> Self { - todo!() +impl TryFrom<DiscordUser> for User { + type Error = AuthError; + + fn try_from(user_data: DiscordUser) -> Result<Self, Self::Error> { + match (&user_data.email, user_data.verified) { + (None, _) => Err(AuthError::MissingEmail), + (_, false) => Err(AuthError::EmailNotVerified), + (Some(_), true) => Ok(Self {}), + } } } @@ -47,84 +55,23 @@ impl AuthServiceDiscord { #[async_trait] impl OauthDriver for AuthServiceDiscord { async fn get_user(&self, client: &AuthHttpClient, code: &str) -> Result<User, AuthError> { - // Get an auth token - let token = self - .client - .exchange_code(AuthorizationCode::new(code.to_owned())) - .request_async(client) - .await - .unwrap(); - // Fetch user data from discord - let user_data: DiscordUser = 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::<DiscordUser>() - .await - .unwrap(); - - Ok(user_data.into()) + crate::util::get_user::<DiscordUser>( + &self.client, + client, + code, + "https://discordapp.com/api/users/@me", + ) + .await } - async fn validate_session(&self, cookie: &str, state: &str) -> Result<(), AuthError> { - let id = Session::id_from_cookie_value(cookie)?; - let cache_key = CacheKey::Session(&id); - let mut cache = self.cache.get().await.unwrap(); - let session = cache.get::<_, String>(&cache_key).await?; - let session: Session = - serde_json::from_str(&session).map_err(|_e| AuthError::InvalidSession)?; - - match session.validate() { - Some(session) => { - // Extract the CSRF token from the session - let stored_csrf_token = session.get::<CsrfToken>(CSRF_TOKEN); - - if let Some(stored) = stored_csrf_token { - // Cleanup the CSRF token session - cache.del::<_, ()>(cache_key).await?; - // Validate CSRF token is the same as the one in the auth request - if *stored.secret() != state { - return Err(AuthError::TokenMismatch); - } else { - return Ok(()); - } - } else { - return Err(AuthError::NoCSRFToken); - } - } - None => return Err(AuthError::MissingSession), - } + async fn validate_session(&self, cookie: &str, state: &str) -> Result<(), AuthError> { + crate::util::validate_session(&self.cache, cookie, state).await } - async fn create_oauth_session(&self) -> Result<SessionResponse, AuthError> { - let (auth_url, csrf_token) = self - .client - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new("identify".to_string())) - .url(); - - let mut session = Session::new(); - session.insert(CSRF_TOKEN, &csrf_token).unwrap(); - let cache_key = CacheKey::Session(session.id()); - let mut cache = self.cache.get().await.unwrap(); - cache - .set::<_, _, ()>( - cache_key, - serde_json::to_string(&session).or(Err(AuthError::InvalidSession))?, - ) - .await?; - let cookie = session - .into_cookie_value() - .ok_or(AuthError::MissingSession)?; - - Ok(SessionResponse { - cookie_value: cookie, - auth_url, - }) + async fn create_oauth_session(&self) -> Result<SessionResponse, AuthError> { + crate::util::create_oauth_session(&self.client, &self.cache, &["identify", "email"]).await } + async fn save_session(&self, user: &User) -> Result<(), AuthError> { todo!() } |
