use std::{ collections::HashMap, env, sync::{Arc, Mutex}, }; use async_trait::async_trait; use chrono::Utc; use openidconnect::{AccessToken, RefreshToken}; use reqwest::Url; use crate::{ auth::{ store_authenticated_session, AuthenticatedSession, Authenticator, SessionId, }, error::{self, BridgeError}, }; pub struct FakeAuthenticator { login_cache: Arc>>>, } impl FakeAuthenticator { pub fn new() -> Self { Self { login_cache: Arc::new(Mutex::new(HashMap::new())), } } } impl Default for FakeAuthenticator { fn default() -> Self { Self::new() } } #[async_trait] impl Authenticator for FakeAuthenticator { async fn user_info( &self, session: &mut AuthenticatedSession, ) -> Result { let user: String = self .login_cache .lock() .unwrap() .get(&session.session_id) .and_then(|u| u.as_ref()) .ok_or(BridgeError::NotLoggedIn)? .clone(); Ok(user) } async fn authenticate( &self, pool: &sqlx::PgPool, session_id: SessionId, auth_params: HashMap, ) -> Result { let user = auth_params .get("user") .ok_or(BridgeError::Internal("missing 'user' param".to_string()))?; self.login_cache .lock() .unwrap() .insert(session_id.clone(), Some(user.clone())); let mut session = AuthenticatedSession::new( user.clone(), session_id, Utc::now() + chrono::Duration::days(10000), AccessToken::new("fake".to_string()), RefreshToken::new("fake".to_string()), ); store_authenticated_session(pool, &mut session).await?; Ok(session) } async fn get_login_url(&self) -> (SessionId, reqwest::Url) { let auth_url = Url::parse(&format!( "{}/api/fake_login", env::var("APP_URL").unwrap() )) .unwrap(); let user_id = SessionId::new(); self.login_cache .lock() .unwrap() .insert(user_id.clone(), None); (user_id, auth_url) } }