From 19c25138f88acf19c9a959a58de4f58e54026ebc Mon Sep 17 00:00:00 2001 From: rtkay123 Date: Sat, 4 Apr 2026 10:51:18 +0200 Subject: feat: connect to db --- crates/api-auth/Cargo.toml | 23 +++++++++++++ crates/api-auth/src/discord/mod.rs | 30 +++++++++++++++++ crates/api-auth/src/error.rs | 25 ++++++++++++++ crates/api-auth/src/lib.rs | 69 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 crates/api-auth/Cargo.toml create mode 100644 crates/api-auth/src/discord/mod.rs create mode 100644 crates/api-auth/src/error.rs create mode 100644 crates/api-auth/src/lib.rs (limited to 'crates/api-auth') diff --git a/crates/api-auth/Cargo.toml b/crates/api-auth/Cargo.toml new file mode 100644 index 0000000..7df9411 --- /dev/null +++ b/crates/api-auth/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "api-auth" +version = "0.0.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true +homepage.workspace = true + +[dependencies] +api-core = { workspace = true, features = ["auth", "users"] } +async-trait.workspace = true +oauth2 = "5.0.0" +secrecy.workspace = true +serde.workspace = true +sqlx.workspace = true +thiserror.workspace = true +utoipa = { workspace = true, optional = true } +url.workspace = true + +[features] +discord = [] +utoipa = ["dep:utoipa", "serde/derive"] diff --git a/crates/api-auth/src/discord/mod.rs b/crates/api-auth/src/discord/mod.rs new file mode 100644 index 0000000..a39722d --- /dev/null +++ b/crates/api-auth/src/discord/mod.rs @@ -0,0 +1,30 @@ +use api_core::models::user::User; +use async_trait::async_trait; +use sqlx::PgPool; + +use crate::{BasicClient, OauthDriver, error::AuthError}; + +#[derive(Clone, Debug)] +pub struct AuthServiceDiscord { + database: PgPool, + client: BasicClient, +} + +impl AuthServiceDiscord { + pub fn new(database: PgPool, client: BasicClient) -> Self { + Self { database, client } + } +} + +#[async_trait] +impl OauthDriver for AuthServiceDiscord { + async fn get_auth_token(&self) -> Result { + todo!() + } + async fn get_user(&self) -> Result { + todo!() + } + async fn create_session(&self, _user: &User) { + todo!() + } +} diff --git a/crates/api-auth/src/error.rs b/crates/api-auth/src/error.rs new file mode 100644 index 0000000..ec60e51 --- /dev/null +++ b/crates/api-auth/src/error.rs @@ -0,0 +1,25 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum AuthClientError { + #[error("missing field: {0}")] + MissingField(&'static str), + #[error("invalid auth url: {0}")] + InvalidAuthUrl(#[from] oauth2::url::ParseError), + #[error("invalid token url: {0}")] + InvalidTokenUrl(#[source] oauth2::url::ParseError), + #[error("invalid redirect url: {0}")] + InvalidRedirectUrl(#[source] oauth2::url::ParseError), +} + +#[derive(Debug, Error)] +pub enum AuthError { + #[error("missing field: {0}")] + MissingField(&'static str), + #[error("invalid auth url: {0}")] + InvalidAuthUrl(#[from] oauth2::url::ParseError), + #[error("invalid token url: {0}")] + InvalidTokenUrl(#[source] oauth2::url::ParseError), + #[error("invalid redirect url: {0}")] + InvalidRedirectUrl(#[source] oauth2::url::ParseError), +} diff --git a/crates/api-auth/src/lib.rs b/crates/api-auth/src/lib.rs new file mode 100644 index 0000000..284b772 --- /dev/null +++ b/crates/api-auth/src/lib.rs @@ -0,0 +1,69 @@ +#[cfg(feature = "discord")] +pub mod discord; + +mod error; +use api_core::auth::AuthClientConfig; +use api_core::auth::provider::OauthProvider; +use api_core::models::user::User; +pub use error::AuthClientError; + +use oauth2::{EndpointNotSet, EndpointSet}; + +type C = oauth2::basic::BasicClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointSet, +>; + +#[derive(Clone, Debug)] +pub struct BasicClient(C); + +#[async_trait::async_trait] +pub trait OauthDriver: Send + Sync + std::fmt::Debug { + async fn get_auth_token(&self) -> Result; + async fn get_user(&self) -> Result; + async fn create_session(&self, user: &User); +} + +use oauth2::{AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl}; +use sqlx::PgPool; +use std::collections::HashMap; +use std::sync::Arc; +use std::{convert::TryFrom, ops::Deref}; + +use crate::error::AuthError; + +pub struct OauthService { + clients: HashMap>, +} + +impl Deref for BasicClient { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl TryFrom for BasicClient { + type Error = AuthClientError; + + fn try_from(value: AuthClientConfig) -> Result { + let auth_url = AuthUrl::new(value.auth_url).map_err(AuthClientError::InvalidAuthUrl)?; + + let token_url = TokenUrl::new(value.token_uri).map_err(AuthClientError::InvalidTokenUrl)?; + + let redirect_url = + RedirectUrl::new(value.redirect_uri).map_err(AuthClientError::InvalidRedirectUrl)?; + + Ok(Self( + oauth2::basic::BasicClient::new(ClientId::new(value.client_id)) + .set_client_secret(ClientSecret::new(value.client_secret)) + .set_auth_uri(auth_url) + .set_token_uri(token_url) + .set_redirect_uri(redirect_url), + )) + } +} -- cgit v1.2.3