use api_core::models::user::User; use async_session::{Session, serde_json}; use async_trait::async_trait; use oauth2::{AuthorizationCode, CsrfToken, TokenResponse}; use redis::AsyncCommands; use serde::{Deserialize, Serialize}; use sh_util::cache::{CacheKey, RedisManager}; use sqlx::PgPool; use crate::{ BasicClient, CSRF_TOKEN, OauthDriver, SessionResponse, client::AuthHttpClient, error::AuthError, }; // The user data we'll get back from Discord. // https://discord.com/developers/docs/resources/user#user-object-user-structure #[derive(Debug, Serialize, Deserialize)] struct DiscordUser { id: String, avatar: Option, username: String, discriminator: String, email: Option, verified: bool, } impl TryFrom for User { type Error = AuthError; fn try_from(user_data: DiscordUser) -> Result { match (&user_data.email, user_data.verified) { (None, _) => Err(AuthError::MissingEmail), (_, false) => Err(AuthError::EmailNotVerified), (Some(_), true) => Ok(Self {}), } } } #[derive(Clone)] pub struct AuthServiceDiscord { database: PgPool, cache: RedisManager, client: BasicClient, } impl AuthServiceDiscord { pub fn new(database: PgPool, client: BasicClient, cache: RedisManager) -> Self { Self { database, client, cache, } } } #[async_trait] impl OauthDriver for AuthServiceDiscord { async fn get_user(&self, client: &AuthHttpClient, code: &str) -> Result { crate::util::get_user::( &self.client, client, code, "https://discordapp.com/api/users/@me", ) .await } 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 { crate::util::create_oauth_session(&self.client, &self.cache, &["identify", "email"]).await } async fn save_session(&self, user: &User) -> Result<(), AuthError> { todo!() } }