aboutsummaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorrtkay123 <dev@kanjala.com>2026-02-02 17:09:32 +0200
committerrtkay123 <dev@kanjala.com>2026-02-02 17:09:32 +0200
commit1f76530bc5001d9a9088f269db6c03cf287b67e6 (patch)
tree99b4873b9813570236fdc4bb71c444c958036e58 /src/server
parent549d98f3b457ddfc6dffbe2fad406da4ac50ebc7 (diff)
downloadsellershut-1f76530bc5001d9a9088f269db6c03cf287b67e6.tar.bz2
sellershut-1f76530bc5001d9a9088f269db6c03cf287b67e6.zip
feat: create auth session
Diffstat (limited to 'src/server')
-rw-r--r--src/server/driver/auth.rs39
-rw-r--r--src/server/driver/mod.rs50
-rw-r--r--src/server/mod.rs2
-rw-r--r--src/server/routes/auth/discord.rs8
-rw-r--r--src/server/routes/auth/mod.rs8
-rw-r--r--src/server/state/mod.rs6
6 files changed, 106 insertions, 7 deletions
diff --git a/src/server/driver/auth.rs b/src/server/driver/auth.rs
index 9215372..28e9285 100644
--- a/src/server/driver/auth.rs
+++ b/src/server/driver/auth.rs
@@ -1,8 +1,17 @@
+use anyhow::Result;
+use async_session::{Session, SessionStore};
+use async_trait::async_trait;
use bon::Builder;
use oauth2::{AuthUrl, ClientId, ClientSecret, EndpointNotSet, EndpointSet, RedirectUrl, TokenUrl};
use secrecy::{ExposeSecret, SecretString};
+use tracing::{instrument, trace};
-#[derive(Builder)]
+use crate::server::driver::Services;
+
+pub(super) static COOKIE_NAME: &str = "SESSION";
+pub(super) static CSRF_TOKEN: &str = "csrf_token";
+
+#[derive(Builder, Debug)]
pub struct ClientOptions {
client_id: String,
client_secret: SecretString,
@@ -20,6 +29,7 @@ pub type OauthClient = oauth2::basic::BasicClient<
>;
pub fn oauth_client(opts: &ClientOptions) -> anyhow::Result<OauthClient> {
+ dbg!(&opts);
let redirect_url = RedirectUrl::new(opts.redirect_url.to_owned())?;
let client_id = ClientId::new(opts.client_id.to_owned());
let auth_url = AuthUrl::new(opts.auth_url.to_owned())?;
@@ -32,3 +42,30 @@ pub fn oauth_client(opts: &ClientOptions) -> anyhow::Result<OauthClient> {
.set_token_uri(token_url)
.set_redirect_uri(redirect_url))
}
+
+#[async_trait]
+impl SessionStore for Services {
+ #[instrument(skip(self))]
+ async fn load_session(&self, cookie_value: String) -> Result<Option<Session>> {
+ let id = Session::id_from_cookie_value(&cookie_value)?;
+ let mut connection = self.database.acquire().await?;
+
+ todo!()
+ }
+
+ #[instrument(skip(self, session), fields(id = session.id()))]
+ async fn store_session(&self, session: Session) -> Result<Option<String>> {
+ let id = session.id();
+ trace!("storing session");
+ let mut connection = self.database.acquire().await?;
+ Ok(session.into_cookie_value())
+ }
+
+ async fn destroy_session(&self, session: Session) -> Result<()> {
+ todo!()
+ }
+
+ async fn clear_store(&self) -> Result<()> {
+ todo!()
+ }
+}
diff --git a/src/server/driver/mod.rs b/src/server/driver/mod.rs
index c006cb0..2debff2 100644
--- a/src/server/driver/mod.rs
+++ b/src/server/driver/mod.rs
@@ -1,11 +1,21 @@
#[cfg(feature = "oauth")]
pub mod auth;
+#[cfg(feature = "oauth")]
+use async_session::Session;
use async_trait::async_trait;
+#[cfg(feature = "oauth")]
+use axum::{
+ http::HeaderMap,
+ response::{IntoResponse, Redirect},
+};
+#[cfg(feature = "oauth")]
+use oauth2::CsrfToken;
use sqlx::PgPool;
use crate::{config::DatabaseOptions, server::state::database};
+#[derive(Debug, Clone)]
pub struct Services {
database: PgPool,
// oauth: OauthClient,
@@ -22,6 +32,13 @@ impl Services {
#[async_trait]
pub trait SellershutDriver: Send + Sync + 'static {
async fn hello(&self);
+
+ #[cfg(feature = "oauth")]
+ async fn create_auth_session(
+ &self,
+ csrf_token: &CsrfToken,
+ auth_url: &url::Url,
+ ) -> anyhow::Result<(HeaderMap, Redirect)>;
}
#[async_trait]
@@ -29,4 +46,37 @@ impl SellershutDriver for Services {
async fn hello(&self) {
todo!()
}
+
+ #[cfg(feature = "oauth")]
+ async fn create_auth_session(
+ &self,
+ csrf_token: &CsrfToken,
+ auth_url: &url::Url,
+ ) -> anyhow::Result<(HeaderMap, Redirect)> {
+ use anyhow::Context;
+ use async_session::SessionStore;
+ use axum::{
+ http::{HeaderMap, header::SET_COOKIE},
+ response::Redirect,
+ };
+
+ use crate::server::driver::auth::{COOKIE_NAME, CSRF_TOKEN};
+
+ let mut session = Session::new();
+ session.insert(CSRF_TOKEN, csrf_token)?;
+
+ let res = self
+ .store_session(session)
+ .await?
+ .context("missing csrf token")?;
+
+ let cookie = format!("{COOKIE_NAME}={res}; SameSite=Lax; HttpOnly; Secure; Path=/");
+ let mut headers = HeaderMap::new();
+ headers.insert(
+ SET_COOKIE,
+ cookie.parse().context("failed to parse cookie")?,
+ );
+
+ Ok((headers, Redirect::to(auth_url.as_str())))
+ }
}
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 2050758..7357957 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -7,7 +7,7 @@ pub mod state;
use std::time::Duration;
-use activitypub_federation::config::{FederationConfig, FederationMiddleware};
+use activitypub_federation::config::FederationMiddleware;
use axum::{
Router,
http::{HeaderName, StatusCode},
diff --git a/src/server/routes/auth/discord.rs b/src/server/routes/auth/discord.rs
index b141ce7..b0305f6 100644
--- a/src/server/routes/auth/discord.rs
+++ b/src/server/routes/auth/discord.rs
@@ -12,6 +12,12 @@ pub(super) async fn discord_auth(data: Data<AppState>) -> Result<impl IntoRespon
.authorize_url(CsrfToken::new_random)
.add_scope(Scope::new("identify".to_string()))
.url();
+ dbg!(&auth_url);
- Ok(String::default())
+ let response = data
+ .driver
+ .create_auth_session(&csrf_token, &auth_url)
+ .await?;
+
+ Ok(response)
}
diff --git a/src/server/routes/auth/mod.rs b/src/server/routes/auth/mod.rs
index b80c565..f0da7cd 100644
--- a/src/server/routes/auth/mod.rs
+++ b/src/server/routes/auth/mod.rs
@@ -50,10 +50,14 @@ pub struct OAuthDoc;
)
)]
#[axum::debug_handler]
+#[cfg(feature = "oauth")]
pub async fn auth(
Query(params): Query<Params>,
data: Data<AppState>,
) -> Result<impl IntoResponse, AppError> {
- dbg!(&params);
- Ok(String::default())
+
+ match params.provider {
+ #[cfg(feature = "oauth-discord")]
+ OauthProvider::Discord => discord::discord_auth(data),
+ }.await
}
diff --git a/src/server/state/mod.rs b/src/server/state/mod.rs
index 03e8c70..c86052d 100644
--- a/src/server/state/mod.rs
+++ b/src/server/state/mod.rs
@@ -6,19 +6,20 @@ use std::sync::Arc;
#[cfg(feature = "oauth-discord")]
use url::Url;
+use crate::{config::Config, server::driver::SellershutDriver};
#[cfg(feature = "oauth-discord")]
use crate::{config::DiscordOauth, server::driver::auth::OauthClient};
-use crate::{config::Config, server::driver::SellershutDriver};
#[derive(Clone)]
pub struct AppState {
- driver: Arc<dyn SellershutDriver>,
+ pub driver: Arc<dyn SellershutDriver>,
#[cfg(feature = "oauth-discord")]
pub oauth_discord: OauthClient,
}
impl AppState {
pub async fn new(config: &Config, driver: impl SellershutDriver) -> anyhow::Result<Self> {
+ dbg!(&config);
Ok(Self {
driver: Arc::new(driver),
#[cfg(feature = "oauth-discord")]
@@ -30,6 +31,7 @@ impl AppState {
#[cfg(feature = "oauth-discord")]
fn discord_client(disc: &DiscordOauth, redirect: &Url) -> anyhow::Result<OauthClient> {
use crate::server::driver::{self, auth::ClientOptions};
+ dbg!(&disc);
let discord_opts = ClientOptions::builder()
.client_id(disc.client_id.to_owned())