diff --git a/visions/server/migrations/01-initial-db/up.sql b/visions/server/migrations/01-initial-db/up.sql index 3e822af..29463cd 100644 --- a/visions/server/migrations/01-initial-db/up.sql +++ b/visions/server/migrations/01-initial-db/up.sql @@ -1,11 +1,18 @@ CREATE TABLE users( uuid TEXT PRIMARY KEY, - name TEXT, + name TEXT UNIQUE, password TEXT, admin BOOLEAN, enabled BOOLEAN ); +CREATE TABLE sessions( + id TEXT PRIMARY KEY, + user_id TEXT, + + FOREIGN KEY(user_id) REFERENCES users(uuid) +); + CREATE TABLE games( uuid TEXT PRIMARY KEY, name TEXT @@ -28,5 +35,3 @@ CREATE TABLE roles( FOREIGN KEY(game_id) REFERENCES games(uuid) ); -INSERT INTO users VALUES ("admin", "admin", "", true, true); - diff --git a/visions/server/src/core.rs b/visions/server/src/core.rs index 2593128..4eaeac0 100644 --- a/visions/server/src/core.rs +++ b/visions/server/src/core.rs @@ -10,7 +10,7 @@ use uuid::Uuid; use crate::{ asset_db::{self, AssetId, Assets}, - database::{CharacterId, Database, UserId}, + database::{CharacterId, Database, SessionId, UserId}, types::{AppError, FatalError, Game, Message, Tabletop, User, RGB}, }; @@ -61,7 +61,7 @@ impl Core { pub async fn status(&self) -> ResultExt { let mut state = self.0.write().await; - let admin_user = return_error!(match state.db.user(UserId::from("admin")).await { + let admin_user = return_error!(match state.db.user(&UserId::from("admin")).await { Ok(Some(admin_user)) => ok(admin_user), Ok(None) => { return ok(Status { @@ -106,6 +106,15 @@ impl Core { } } + pub async fn user_by_username(&self, username: &str) -> ResultExt, AppError, FatalError> { + let state = self.0.read().await; + match state.db.user_by_username(username).await { + Ok(Some(user_row)) => ok(Some(User::from(user_row))), + Ok(None) => ok(None), + Err(err) => fatal(err), + } + } + pub async fn list_users(&self) -> ResultExt, AppError, FatalError> { let users = self.0.write().await.db.users().await; match users { @@ -206,7 +215,7 @@ impl Core { password: String, ) -> ResultExt<(), AppError, FatalError> { let mut state = self.0.write().await; - let user = match state.db.user(uuid.clone()).await { + let user = match state.db.user(&uuid).await { Ok(Some(row)) => row, Ok(None) => return error(AppError::NotFound(uuid.as_str().to_owned())), Err(err) => return fatal(err), @@ -221,10 +230,13 @@ impl Core { } } - pub async fn auth(&self, username: String, password: String) -> ResultExt { + pub async fn auth(&self, username: &str, password: &str) -> ResultExt { let state = self.0.write().await; - match state.db.user_by_username(username).await { - Ok(Some(row)) if (row.password == password) => ok(row.id), + match state.db.user_by_username(&username).await { + Ok(Some(row)) if (row.password == password) => { + let session_id = state.db.create_session(row.id).await.unwrap(); + ok(session_id) + } Ok(_) => error(AppError::AuthFailed), Err(err) => fatal(err), } @@ -244,7 +256,7 @@ mod test { database::{DbConn, DiskDb}, }; - fn test_core() -> Core { + async fn test_core() -> Core { let assets = MemoryAssets::new(vec![ ( AssetId::from("asset_1"), @@ -274,19 +286,21 @@ mod test { ]); let memory_db: Option = None; let conn = DbConn::new(memory_db); + conn.save_user(None, "admin", "aoeu", true, true).await.unwrap(); + conn.save_user(None, "gm_1", "aoeu", false, true).await.unwrap(); Core::new(assets, conn) } #[tokio::test] async fn it_lists_available_images() { - let core = test_core(); + let core = test_core().await; let image_paths = core.available_images().await; assert_eq!(image_paths.len(), 2); } #[tokio::test] async fn it_retrieves_an_asset() { - let core = test_core(); + let core = test_core().await; assert_matches!(core.get_asset(AssetId::from("asset_1")).await, ResultExt::Ok((mime, data)) => { assert_eq!(mime.type_(), mime::IMAGE); assert_eq!(data, "abcdefg".as_bytes()); @@ -295,7 +309,7 @@ mod test { #[tokio::test] async fn it_can_retrieve_the_default_tabletop() { - let core = test_core(); + let core = test_core().await; assert_matches!(core.tabletop().await, Tabletop{ background_color, background_image } => { assert_eq!(background_color, DEFAULT_BACKGROUND_COLOR); assert_eq!(background_image, None); @@ -304,7 +318,7 @@ mod test { #[tokio::test] async fn it_can_change_the_tabletop_background() { - let core = test_core(); + let core = test_core().await; assert_matches!( core.set_background_image(AssetId::from("asset_1")).await, ResultExt::Ok(()) @@ -317,7 +331,7 @@ mod test { #[tokio::test] async fn it_sends_notices_to_clients_on_tabletop_change() { - let core = test_core(); + let core = test_core().await; let client_id = core.register_client().await; let mut receiver = core.connect_client(client_id).await; @@ -336,4 +350,21 @@ mod test { None => panic!("receiver did not get a message"), } } + + #[tokio::test] + async fn it_creates_a_sessionid_on_successful_auth() { + let core = test_core().await; + match core.auth("admin", "aoeu").await { + ResultExt::Ok(session_id) => { + let st = core.0.read().await; + match st.db.session(session_id).await { + Ok(Some(user_row)) => assert_eq!(user_row.name, "admin"), + Ok(None) => panic!("no matching user row for the session id"), + Err(err) => panic!("{}", err), + } + }, + ResultExt::Err(err) => panic!("{}", err), + ResultExt::Fatal(err) => panic!("{}", err), + } + } } diff --git a/visions/server/src/database.rs b/visions/server/src/database.rs index b85df30..a741594 100644 --- a/visions/server/src/database.rs +++ b/visions/server/src/database.rs @@ -24,11 +24,13 @@ lazy_static! { #[derive(Debug)] enum Request { Charsheet(CharacterId), + CreateSession(UserId), Games, + SaveUser(Option, String, String, bool, bool), + Session(SessionId), User(UserId), UserByUsername(String), Users, - SaveUser(Option, String, String, bool, bool), } #[derive(Debug)] @@ -40,10 +42,12 @@ struct DatabaseRequest { #[derive(Debug)] enum DatabaseResponse { Charsheet(Option), + CreateSession(SessionId), Games(Vec), + SaveUser(UserId), + Session(Option), User(Option), Users(Vec), - SaveUser(UserId), } #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] @@ -80,6 +84,40 @@ impl FromSql for UserId { } } +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct SessionId(String); + +impl SessionId { + pub fn new() -> Self { + Self(format!("{}", Uuid::new_v4().hyphenated())) + } + + pub fn as_str<'a>(&'a self) -> &'a str { + &self.0 + } +} + +impl From<&str> for SessionId { + fn from(s: &str) -> Self { + Self(s.to_owned()) + } +} + +impl From for SessionId { + fn from(s: String) -> Self { + Self(s) + } +} + +impl FromSql for SessionId { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + match value { + ValueRef::Text(text) => Ok(Self::from(String::from_utf8(text.to_vec()).unwrap())), + _ => unimplemented!(), + } + } +} + #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct GameId(String); @@ -177,14 +215,20 @@ pub struct CharsheetRow { pub data: serde_json::Value, } +#[derive(Clone, Debug)] +pub struct SessionRow { + id: SessionId, + user_id: SessionId, +} + #[async_trait] pub trait Database: Send + Sync { - async fn user(&mut self, _: UserId) -> Result, FatalError>; + async fn user(&mut self, _: &UserId) -> Result, FatalError>; - async fn user_by_username(&self, _: String) -> Result, FatalError>; + async fn user_by_username(&self, _: &str) -> Result, FatalError>; async fn save_user( - &mut self, + &self, user_id: Option, name: &str, password: &str, @@ -197,6 +241,10 @@ pub trait Database: Send + Sync { async fn games(&mut self) -> Result, FatalError>; async fn character(&mut self, id: CharacterId) -> Result, FatalError>; + + async fn session(&self, id: SessionId) -> Result, FatalError>; + + async fn create_session(&self, id: UserId) -> Result; } pub struct DiskDb { @@ -268,7 +316,7 @@ impl DiskDb { Ok(DiskDb { conn }) } - fn user(&self, id: UserId) -> Result, FatalError> { + fn user(&self, id: &UserId) -> Result, FatalError> { let mut stmt = self .conn .prepare("SELECT uuid, name, password, admin, enabled FROM users WHERE uuid=?") @@ -293,13 +341,13 @@ impl DiskDb { } } - fn user_by_username(&self, username: String) -> Result, FatalError> { + fn user_by_username(&self, username: &str) -> Result, FatalError> { let mut stmt = self .conn .prepare("SELECT uuid, name, password, admin, enabled FROM users WHERE name=?") .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; let items: Vec = stmt - .query_map([username.as_str()], |row| { + .query_map([username], |row| { Ok(UserRow { id: row.get(0).unwrap(), name: row.get(1).unwrap(), @@ -361,9 +409,7 @@ impl DiskDb { Some(user_id) => { let mut stmt = self .conn - .prepare( - "UPDATE users SET name=?, password=?, admin=?, enabled=? WHERE uuid=?", - ) + .prepare("UPDATE users SET name=?, password=?, admin=?, enabled=? WHERE uuid=?") .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; stmt.execute((name, password, admin, enabled, user_id.as_str())) .unwrap(); @@ -394,6 +440,51 @@ impl DiskDb { } } + fn session(&self, session_id: &SessionId) -> Result, FatalError> { + let mut stmt = self.conn + .prepare("SELECT u.uuid, u.name, u.password, u.admin, u.enabled FROM sessions s INNER JOIN users u ON u.uuid = s.user_id WHERE s.id = ?") + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + + let items: Vec = stmt + .query_map([session_id.as_str()], |row| { + Ok(UserRow { + id: row.get(0).unwrap(), + name: row.get(1).unwrap(), + password: row.get(2).unwrap(), + admin: row.get(3).unwrap(), + enabled: row.get(4).unwrap(), + }) + }) + .unwrap() + .collect::, rusqlite::Error>>() + .unwrap(); + match &items[..] { + [] => Ok(None), + [item] => Ok(Some(item.clone())), + _ => Err(FatalError::NonUniqueDatabaseKey( + session_id.as_str().to_owned(), + )), + } + } + + fn create_session(&self, user_id: &UserId) -> Result { + match self.user(user_id) { + Ok(Some(_)) => { + let mut stmt = self + .conn + .prepare("INSERT INTO sessions VALUES (?, ?)") + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + + let session_id = SessionId::new(); + stmt.execute((session_id.as_str(), user_id.as_str())) + .unwrap(); + Ok(session_id) + } + Ok(None) => Err(FatalError::DatabaseKeyMissing), + Err(err) => Err(err), + } + } + fn character(&self, id: CharacterId) -> Result, FatalError> { let mut stmt = self .conn @@ -456,7 +547,6 @@ async fn db_handler(db: DiskDb, requestor: Receiver) { match req { Request::Charsheet(id) => { let sheet = db.character(id); - println!("sheet retrieved: {:?}", sheet); match sheet { Ok(sheet) => { tx.send(DatabaseResponse::Charsheet(sheet)).await.unwrap(); @@ -464,11 +554,17 @@ async fn db_handler(db: DiskDb, requestor: Receiver) { _ => unimplemented!(), } } + Request::CreateSession(id) => { + let session_id = db.create_session(&id).unwrap(); + tx.send(DatabaseResponse::CreateSession(session_id)) + .await + .unwrap(); + } Request::Games => { unimplemented!(); } Request::User(uid) => { - let user = db.user(uid); + let user = db.user(&uid); match user { Ok(user) => { tx.send(DatabaseResponse::User(user)).await.unwrap(); @@ -477,14 +573,20 @@ async fn db_handler(db: DiskDb, requestor: Receiver) { } } Request::UserByUsername(username) => { - let user = db.user_by_username(username); + let user = db.user_by_username(&username); match user { Ok(user) => tx.send(DatabaseResponse::User(user)).await.unwrap(), err => panic!("{:?}", err), } } Request::SaveUser(user_id, username, password, admin, enabled) => { - let user_id = db.save_user(user_id, username.as_ref(), password.as_ref(), admin, enabled); + let user_id = db.save_user( + user_id, + username.as_ref(), + password.as_ref(), + admin, + enabled, + ); match user_id { Ok(user_id) => { tx.send(DatabaseResponse::SaveUser(user_id)).await.unwrap(); @@ -492,6 +594,13 @@ async fn db_handler(db: DiskDb, requestor: Receiver) { err => panic!("{:?}", err), } } + Request::Session(session_id) => { + let user = db.session(&session_id); + match user { + Ok(user) => tx.send(DatabaseResponse::Session(user)).await.unwrap(), + err => panic!("{:?}", err), + } + } Request::Users => { let users = db.users(); match users { @@ -529,12 +638,12 @@ impl DbConn { #[async_trait] impl Database for DbConn { - async fn user(&mut self, uid: UserId) -> Result, FatalError> { + async fn user(&mut self, uid: &UserId) -> Result, FatalError> { let (tx, rx) = bounded::(1); let request = DatabaseRequest { tx, - req: Request::User(uid), + req: Request::User(uid.clone()), }; match self.conn.send(request).await { @@ -549,12 +658,12 @@ impl Database for DbConn { } } - async fn user_by_username(&self, username: String) -> Result, FatalError> { + async fn user_by_username(&self, username: &str) -> Result, FatalError> { let (tx, rx) = bounded::(1); let request = DatabaseRequest { tx, - req: Request::UserByUsername(username), + req: Request::UserByUsername(username.to_owned()), }; match self.conn.send(request).await { @@ -570,7 +679,7 @@ impl Database for DbConn { } async fn save_user( - &mut self, + &self, user_id: Option, name: &str, password: &str, @@ -661,6 +770,46 @@ impl Database for DbConn { Err(_) => Err(FatalError::DatabaseConnectionLost), } } + + async fn session(&self, id: SessionId) -> Result, FatalError> { + let (tx, rx) = bounded::(1); + + let request = DatabaseRequest { + tx, + req: Request::Session(id), + }; + + match self.conn.send(request).await { + Ok(()) => (), + Err(_) => return Err(FatalError::DatabaseConnectionLost), + }; + + match rx.recv().await { + Ok(DatabaseResponse::Session(row)) => Ok(row), + Ok(_) => Err(FatalError::MessageMismatch), + Err(_) => Err(FatalError::DatabaseConnectionLost), + } + } + + async fn create_session(&self, id: UserId) -> Result { + let (tx, rx) = bounded::(1); + + let request = DatabaseRequest { + tx, + req: Request::CreateSession(id), + }; + + match self.conn.send(request).await { + Ok(()) => (), + Err(_) => return Err(FatalError::DatabaseConnectionLost), + }; + + match rx.recv().await { + Ok(DatabaseResponse::CreateSession(session_id)) => Ok(session_id), + Ok(_) => Err(FatalError::MessageMismatch), + Err(_) => Err(FatalError::DatabaseConnectionLost), + } + } } #[cfg(test)] @@ -668,7 +817,6 @@ mod test { use std::path::PathBuf; use cool_asserts::assert_matches; - use result_extended::ResultExt; use super::*; @@ -678,7 +826,7 @@ mod test { let no_path: Option = None; let db = DiskDb::new(no_path).unwrap(); - db.save_user(None, "admin", "abcdefg", true, true); + db.save_user(None, "admin", "abcdefg", true, true).unwrap(); let game_id = db.save_game(None, "Candela").unwrap(); (db, game_id) } @@ -699,9 +847,6 @@ mod test { let memory_db: Option = None; let mut conn = DbConn::new(memory_db); - assert_matches!( - conn.character(CharacterId::from("1")).await, - Ok(None) - ); + assert_matches!(conn.character(CharacterId::from("1")).await, Ok(None)); } } diff --git a/visions/server/src/filters/mod.rs b/visions/server/src/filters/mod.rs index adf876d..06b5635 100644 --- a/visions/server/src/filters/mod.rs +++ b/visions/server/src/filters/mod.rs @@ -9,7 +9,11 @@ use warp::{ }; use crate::{ - asset_db::AssetId, core::Core, handlers::{handle_auth, handle_available_images, handle_connect_websocket, handle_file, handle_get_charsheet, handle_get_users, handle_register_client, handle_server_status, handle_set_admin_password, handle_set_background_image, handle_unregister_client, RegisterRequest} + asset_db::AssetId, + core::Core, + handlers::{ + handle_available_images, handle_check_password, handle_connect_websocket, handle_file, handle_get_charsheet, handle_register_client, handle_server_status, handle_set_background_image, handle_unregister_client, RegisterRequest + }, }; fn cors(methods: Vec, headers: Vec) -> Builder @@ -23,6 +27,13 @@ where .allow_headers(headers) } +pub fn route_healthcheck() -> impl Filter + Clone +{ + warp::path!("api" / "v1" / "healthcheck") + .and(warp::get()) + .map(|| warp::reply::reply()) +} + pub fn route_server_status( core: Core, ) -> impl Filter + Clone { @@ -44,7 +55,6 @@ pub fn route_set_bg_image( .with(cors::(vec![Method::PUT], vec![])) } - pub fn route_image( core: Core, ) -> impl Filter + Clone { @@ -76,7 +86,6 @@ pub fn route_register_client( }) } - pub fn route_unregister_client( core: Core, ) -> impl Filter + Clone { @@ -111,7 +120,7 @@ pub fn route_get_charsheet( }) } -pub fn route_check_password( +pub fn route_authenticate( core: Core, ) -> impl Filter + Clone { warp::path!("api" / "v1" / "auth") @@ -119,7 +128,7 @@ pub fn route_check_password( .and(warp::body::json()) .then({ let core = core.clone(); - move |body| handle_auth(core.clone(), body) + move |body| handle_check_password(core.clone(), body) }) + .with(cors::(vec![Method::PUT], vec![])) } - diff --git a/visions/server/src/filters/user_management.rs b/visions/server/src/filters/user_management.rs index 7353c21..d63b809 100644 --- a/visions/server/src/filters/user_management.rs +++ b/visions/server/src/filters/user_management.rs @@ -1,12 +1,12 @@ use warp::{ - http::{header::CONTENT_TYPE, Method}, + http::{header::CONTENT_TYPE, HeaderName, Method}, reply::Reply, Filter, }; use crate::{ core::Core, - handlers::{handle_get_users, handle_set_admin_password}, + handlers::{handle_check_password, handle_get_users, handle_set_admin_password}, }; use super::cors; @@ -37,3 +37,71 @@ pub fn routes_user_management( ) -> impl Filter + Clone { route_get_users(core.clone()).or(route_set_admin_password(core.clone())) } + +pub fn route_check_password( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "auth") + .and(warp::put()) + .and(warp::body::json()) + .then({ + let core = core.clone(); + move |body| handle_check_password(core.clone(), body) + }) + .with(cors::(vec![Method::PUT], vec![])) +} + +#[cfg(test)] +mod test { + use std::{collections::HashMap, path::PathBuf}; + + use result_extended::ResultExt; + + use crate::{asset_db::mocks::MemoryAssets, database::{Database, DbConn, UserId}}; + + use super::*; + + async fn setup() -> Core { + let asset_store = MemoryAssets::new(vec![]); + let memory_file: Option = None; + let db = DbConn::new(memory_file); + db.save_user(None, "admin", "", true, true).await.unwrap(); + Core::new(asset_store, db) + } + + #[tokio::test] + async fn handle_check_password_should_return_a_valid_token() { + let core = setup().await; + match core.list_users().await { + ResultExt::Ok(users) => println!("{:?}", users), + ResultExt::Err(err) => panic!("{}", err), + ResultExt::Fatal(err) => panic!("{}", err), + } + match core.user_by_username("admin").await { + ResultExt::Ok(Some(user)) => { + let _ = core.set_password(UserId::from(user.id), "aoeu".to_owned()).await; + }, + ResultExt::Ok(None) => panic!("expected user wasn't found"), + ResultExt::Err(err) => panic!("{}", err), + ResultExt::Fatal(err) => panic!("{}", err), + } + let filter = route_check_password(core); + let params: HashMap = vec![ + ("username".to_owned(), "admin".to_owned()), + ("password".to_owned(), "aoeu".to_owned()), + ] + .into_iter() + .collect(); + let resp = warp::test::request() + .method("PUT") + .path("/api/v1/auth") + .json(¶ms) + .reply(&filter) + .await; + + println!("response: {}", resp.status()); + assert!(resp.status().is_success()); + println!("resp.body(): {}", String::from_utf8(resp.body().to_vec()).unwrap()); + serde_json::from_slice::(resp.body()).unwrap(); + } +} diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs index 34145e4..2865ff8 100644 --- a/visions/server/src/handlers.rs +++ b/visions/server/src/handlers.rs @@ -47,10 +47,13 @@ where .status(StatusCode::NOT_FOUND) .body(vec![]) .unwrap(), - ResultExt::Err(_) => Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(vec![]) - .unwrap(), + ResultExt::Err(err) => { + println!("request error: {:?}", err); + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(vec![]) + .unwrap() + } ResultExt::Fatal(err) => { panic!("Shutting down with fatal error: {:?}", err); } @@ -262,35 +265,20 @@ pub async fn handle_set_admin_password(core: Core, password: String) -> impl Rep pub struct AuthRequest { username: String, password: String, - } -pub async fn handle_auth(core: Core, auth_request: AuthRequest) -> impl Reply { +pub async fn handle_check_password(core: Core, auth_request: AuthRequest) -> impl Reply { handler(async move { - let userid = return_error!(core.auth(auth_request.username, auth_request.password).await); + let session_id = return_error!( + core.auth(&auth_request.username, &auth_request.password) + .await + ); + println!("handle_check_password: {:?}", session_id); ok(Response::builder() - .header("Access-Control-Allow-Origin", "*") - .header("Access-Control-Allow-Methods", "*") - .header("Access-Control-Allow-Headers", "content-type") .header("Content-Type", "application/json") - .body(serde_json::to_vec(&userid).unwrap()) + .body(serde_json::to_vec(&session_id).unwrap()) .unwrap()) - }).await -} - -#[cfg(test)] -mod test { - use std::path::PathBuf; - - use crate::{asset_db::mocks::MemoryAssets, database::DbConn}; - - use super::*; - - fn setup() -> Core { - let asset_store = MemoryAssets::new(vec![]); - let memory_file: Option = None; - let db = DbConn::new(memory_file); - Core::new(asset_store, db) - } + }) + .await } diff --git a/visions/server/src/main.rs b/visions/server/src/main.rs index 9219215..a6692ec 100644 --- a/visions/server/src/main.rs +++ b/visions/server/src/main.rs @@ -7,13 +7,7 @@ use std::{ use asset_db::{AssetId, FsAssets}; use authdb::AuthError; use database::DbConn; -use filters::{route_available_images, route_check_password, route_get_charsheet, route_image, route_register_client, route_server_status, route_set_bg_image, route_unregister_client, route_websocket, routes_user_management}; -use handlers::{ - handle_auth, handle_available_images, handle_connect_websocket, handle_file, - handle_get_charsheet, handle_get_users, handle_register_client, handle_server_status, - handle_set_admin_password, handle_set_background_image, handle_unregister_client, - RegisterRequest, -}; +use filters::{route_authenticate, route_available_images, route_get_charsheet, route_healthcheck, route_image, route_register_client, route_server_status, route_set_bg_image, route_unregister_client, route_websocket, routes_user_management}; use warp::{ // header, filters::{method, path}, @@ -111,21 +105,13 @@ pub async fn main() { let core = core::Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn); + let unauthenticated_endpoints = route_healthcheck().or(route_authenticate(core.clone())); + let authenticated_endpoints = route_image(core.clone()); - let filter = route_server_status(core.clone()) - .or(route_register_client(core.clone())) - .or(route_unregister_client(core.clone())) - .or(route_websocket(core.clone())) - .or(route_image(core.clone())) - .or(route_available_images(core.clone())) - .or(route_set_bg_image(core.clone())) - .or(routes_user_management(core.clone())) - .or(route_get_charsheet(core.clone())) - .or(route_check_password(core.clone())) - .with(warp::log("visions")) - .recover(handle_rejection); - - let server = warp::serve(filter); + let server = warp::serve(unauthenticated_endpoints + .or(authenticated_endpoints) + .with(warp::log("visions")) + .recover(handle_rejection)); server .run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8001)) .await; diff --git a/visions/server/src/types.rs b/visions/server/src/types.rs index 43cdcf7..15fedf4 100644 --- a/visions/server/src/types.rs +++ b/visions/server/src/types.rs @@ -7,20 +7,23 @@ use crate::{asset_db::AssetId, database::UserRow}; #[derive(Debug, Error)] pub enum FatalError { - #[error("Non-unique database key {0}")] - NonUniqueDatabaseKey(String), - - #[error("Database migrations failed {0}")] - DatabaseMigrationFailure(String), - #[error("Failed to construct a query")] ConstructQueryFailure(String), #[error("Database connection lost")] DatabaseConnectionLost, + #[error("Expected database key is missing")] + DatabaseKeyMissing, + + #[error("Database migrations failed {0}")] + DatabaseMigrationFailure(String), + #[error("Unexpected response for message")] MessageMismatch, + + #[error("Non-unique database key {0}")] + NonUniqueDatabaseKey(String), } impl result_extended::FatalError for FatalError {}