#[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::Redirect}; #[cfg(feature = "oauth")] use oauth2::CsrfToken; use sqlx::PgPool; use crate::{ config::{DatabaseOptions, cache::CacheConfig}, server::state::{cache::RedisManager, database}, }; #[derive(Debug, Clone)] pub struct Services { database: PgPool, cache: RedisManager, } impl Services { pub async fn new(database: &DatabaseOptions, cache: &CacheConfig) -> anyhow::Result { let database = database::connect(database).await?; let cache = RedisManager::new(cache).await?; Ok(Self { database, cache }) } } #[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] 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()))) } }