use std::{collections::HashMap, error::Error, net::SocketAddr, sync::Arc, time::Duration}; use anyhow::anyhow; use async_trait::async_trait; use auth_for_warp::{ build_api_route_filter, handle_auth_errors, with_auth, Auth, AuthConfig, HashedPassword, UserDatabase, UserID, Username, }; use serde_json::json; use tokio::sync::Mutex; use warp::{path, Filter}; #[tokio::main] async fn main() { let database_connection = Arc::new(Mutex::new(SimpleInMemoryDb::new())); let config = AuthConfig { password_salt: "this is a terrible salt".into(), auth_token_issuer: "insert app or organisation name here".into(), auth_token_secret: "this is a really bad secret".into(), auth_token_lifetime: Duration::from_secs(60 * 60), database_connection, }; let auth = Auth::new(config); let auth_routes = build_api_route_filter(&auth); let unsecured_homepage = warp::path::end().then(|| async move { warp::reply::html("hello, world!") }); let secure_page = path!("check_user_id") .and(with_auth(&auth)) .then(|user_id| async move { warp::reply::json(&json!({ "user id": user_id })) }); let all_routes = unsecured_homepage .or(secure_page) .or(auth_routes) .recover(handle_auth_errors); warp::serve(all_routes) .run("127.0.0.1:4000".parse::().unwrap()) .await; } struct SimpleInMemoryDb { storage: HashMap, } impl SimpleInMemoryDb { pub fn new() -> Self { Self { storage: HashMap::new(), } } } #[async_trait] impl UserDatabase for SimpleInMemoryDb { async fn create_user_if_not_exists( &mut self, user_id: &UserID, username: &Username, hashed_password: &HashedPassword, ) -> Result> { if self.storage.contains_key(&username.0) { Ok(self.storage[&username.0.clone()].0.clone()) } else { self.storage.insert( username.0.clone(), (user_id.clone(), hashed_password.clone()), ); Ok(user_id.clone()) } } async fn retreive_user( &self, username: &Username, ) -> Result<(UserID, HashedPassword), Box> { let result = self .storage .get(&username.0) .ok_or_else(|| anyhow!("user not found")) .cloned()?; Ok(result) } }