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 time::OffsetDateTime; use tracing::{instrument, trace}; use crate::server::{driver::Services, entity}; 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, token_url: String, auth_url: String, redirect_url: String, } pub type OauthClient = oauth2::basic::BasicClient< EndpointSet, EndpointNotSet, EndpointNotSet, EndpointNotSet, EndpointSet, >; pub fn oauth_client(opts: &ClientOptions) -> anyhow::Result { 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())?; let token_url = TokenUrl::new(opts.token_url.to_owned())?; let client_secret = ClientSecret::new(opts.client_secret.expose_secret().to_string()); Ok(oauth2::basic::BasicClient::new(client_id) .set_client_secret(client_secret) .set_auth_uri(auth_url) .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> { let id = Session::id_from_cookie_value(&cookie_value)?; let result = sqlx::query_as!( entity::auth::Session, "select * from session where id = $1 and ( expires is null or expires > $2 ) ", id, OffsetDateTime::now_utc() ) .fetch_optional(&self.database) .await? .map(|value| serde_json::from_str(&value.session)); Ok(result.transpose()?) } #[instrument(skip(self, session), fields(id = session.id()))] async fn store_session(&self, session: Session) -> Result> { 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!() } }