From 8e6b652d5e1623a1e8d01a5e3ae993541b664fe1 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 24 Oct 2021 13:20:15 -0600 Subject: [PATCH] Added user_id checking to commands + Refactored to make CommandRequest a trait that all the parameter structs implment + Created handle_command to handle all the preprocessing needed before running the command --- geoffrey_api/src/commands/add_location.rs | 33 ++++++-------- geoffrey_api/src/commands/find.rs | 7 ++- geoffrey_api/src/commands/mod.rs | 45 ++++++++++++++++--- geoffrey_api/src/commands/register.rs | 9 ++-- geoffrey_api/src/helper/mod.rs | 8 ++-- .../models/parameters/add_location_params.rs | 14 ++++++ .../src/models/parameters/find_params.rs | 8 ++++ geoffrey_models/src/models/parameters/mod.rs | 20 ++++----- .../src/models/parameters/register_params.rs | 10 ++++- 9 files changed, 103 insertions(+), 51 deletions(-) diff --git a/geoffrey_api/src/commands/add_location.rs b/geoffrey_api/src/commands/add_location.rs index a977bf2..d6fe6aa 100644 --- a/geoffrey_api/src/commands/add_location.rs +++ b/geoffrey_api/src/commands/add_location.rs @@ -1,19 +1,17 @@ use crate::commands::{Command, RequestType}; use crate::context::Context; -use crate::helper::get_player_from_req; use crate::Result; use geoffrey_db::helper::load_location; use geoffrey_models::models::locations::{Location, LocationDb}; use geoffrey_models::models::parameters::add_location_params::AddLocationParams; -use geoffrey_models::models::parameters::CommandRequest; -use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::CommandLevel; use std::sync::Arc; +use geoffrey_models::models::player::Player; pub struct AddLocation {} impl Command for AddLocation { - type Req = CommandRequest; + type Req = AddLocationParams; type Resp = Location; fn command_name() -> String { @@ -28,22 +26,19 @@ impl Command for AddLocation { CommandLevel::REGISTERED } - fn run_command(ctx: Arc, req: Self::Req) -> Result { - if let Some(player) = get_player_from_req(&ctx.db, &req)? { - let args = &req.arguments; - let location = LocationDb::new( - args.name.as_str(), - args.position, - player.id.unwrap(), - args.tunnel.clone(), - args.loc_type.into(), - ); + fn run_command(ctx: Arc, req: Self::Req, user: Option) -> Result { + let user = user.unwrap(); - let location = ctx.db.insert(location)?; + let location = LocationDb::new( + req.name.as_str(), + req.position, + user.id.unwrap(), + req.tunnel.clone(), + req.loc_type.into(), + ); - load_location(&ctx.db, &location).map_err(|err| err.into()) - } else { - Err(GeoffreyAPIError::PlayerNotRegistered) - } + let location = ctx.db.insert(location)?; + + load_location(&ctx.db, &location).map_err(|err| err.into()) } } diff --git a/geoffrey_api/src/commands/find.rs b/geoffrey_api/src/commands/find.rs index 1e07f2f..f8ff167 100644 --- a/geoffrey_api/src/commands/find.rs +++ b/geoffrey_api/src/commands/find.rs @@ -4,7 +4,6 @@ use crate::Result; use geoffrey_db::helper::load_location; use geoffrey_models::models::locations::{Location, LocationDb}; use geoffrey_models::models::parameters::find_params::FindParams; -use geoffrey_models::models::parameters::CommandRequest; use geoffrey_models::models::player::Player; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::CommandLevel; @@ -13,7 +12,7 @@ use std::sync::Arc; pub struct FindCommand {} impl Command for FindCommand { - type Req = CommandRequest; + type Req = FindParams; type Resp = Vec; fn command_name() -> String { @@ -28,8 +27,8 @@ impl Command for FindCommand { CommandLevel::ALL } - fn run_command(ctx: Arc, req: Self::Req) -> Result { - let query = req.arguments.query.to_lowercase(); + fn run_command(ctx: Arc, req: Self::Req, _: Option) -> Result { + let query = req.query.to_lowercase(); let players: Vec = ctx .db .filter(|_, player: &Player| { diff --git a/geoffrey_api/src/commands/mod.rs b/geoffrey_api/src/commands/mod.rs index 944aec0..e95d27f 100644 --- a/geoffrey_api/src/commands/mod.rs +++ b/geoffrey_api/src/commands/mod.rs @@ -11,6 +11,11 @@ use std::fmt::Debug; use std::sync::Arc; use warp::filters::BoxedFilter; use warp::Filter; +use geoffrey_models::models::player::Player; +use crate::helper::get_player_from_req; +use geoffrey_models::models::response::api_error::GeoffreyAPIError; +use geoffrey_models::models::parameters::CommandRequest; + pub mod add_location; pub mod find; @@ -24,13 +29,44 @@ pub enum RequestType { } pub trait Command { - type Req: Serialize + DeserializeOwned + Send + 'static + Debug; + type Req: CommandRequest; type Resp: Serialize + DeserializeOwned + Send; fn command_name() -> String; fn request_type() -> RequestType; fn command_level() -> CommandLevel; - fn run_command(ctx: Arc, req: Self::Req) -> Result; + fn run_command(ctx: Arc, req: Self::Req, user: Option) -> Result; + + fn user_is_authorized(user: &Option) -> Result<()> { + if Self::command_level() == CommandLevel::ALL { + Ok(()) + } + else { + if let Some(user) = user { + if user.auth_level >= Self::command_level() { + Ok(()) + } + else { + Err(GeoffreyAPIError::PermissionInsufficient) + } + } + else { + Err(GeoffreyAPIError::PlayerNotRegistered) + } + } + } +} + +pub fn handle_command(ctx: Arc, req: T::Req) -> Result { + log::info!("Running command {}", T::command_name()); + log::debug!("Request: {:?}", req); + + let user = get_player_from_req(&ctx.db, &req)?; + + match T::user_is_authorized(&user) { + Ok(_) => T::run_command(ctx, req, user), + Err(e) => Err(e) + } } #[allow(clippy::needless_return)] @@ -39,10 +75,7 @@ pub fn create_command_filter(ctx: Arc) -> BoxedFilter<(impl .and(warp::any().map(move || ctx.clone())) .and(warp::body::json()) .map(|ctx: Arc, req: T::Req| { - log::info!("Running command {}", T::command_name()); - log::debug!("Request: {:?}", req); - - let reply = T::run_command(ctx, req); + let reply = handle_command::(ctx, req); if let Ok(reply) = reply { log::debug!("Successfully processed command"); warp::reply::json(&APIResponse::Response::(reply)) diff --git a/geoffrey_api/src/commands/register.rs b/geoffrey_api/src/commands/register.rs index 4ec6d43..5ddb3f0 100644 --- a/geoffrey_api/src/commands/register.rs +++ b/geoffrey_api/src/commands/register.rs @@ -1,7 +1,6 @@ use crate::commands::{Command, RequestType}; use crate::context::Context; use geoffrey_models::models::parameters::register_params::RegisterParameters; -use geoffrey_models::models::parameters::CommandRequest; use geoffrey_models::models::player::Player; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::CommandLevel; @@ -10,7 +9,7 @@ use std::sync::Arc; pub struct Register {} impl Command for Register { - type Req = CommandRequest; + type Req = RegisterParameters; type Resp = Player; fn command_name() -> String { @@ -25,11 +24,11 @@ impl Command for Register { CommandLevel::ALL } - fn run_command(ctx: Arc, req: Self::Req) -> crate::Result { - let player = Player::new(req.arguments.username.as_str(), req.arguments.user_id); + fn run_command(ctx: Arc, req: Self::Req, _: Option) -> crate::Result { + let player = Player::new(req.username.as_str(), req.new_user_id); ctx.db .insert(player) - .map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string())) + .map_err(GeoffreyAPIError::from) } } diff --git a/geoffrey_api/src/helper/mod.rs b/geoffrey_api/src/helper/mod.rs index af58c27..a7e58c2 100644 --- a/geoffrey_api/src/helper/mod.rs +++ b/geoffrey_api/src/helper/mod.rs @@ -3,12 +3,12 @@ use geoffrey_db::database::Database; use geoffrey_models::models::parameters::CommandRequest; use geoffrey_models::models::player::Player; -pub fn get_player_from_req(db: &Database, req: &CommandRequest) -> Result> { - if let Some(user_id) = &req.user { +pub fn get_player_from_req(db: &Database, req: &T) -> Result> { + if let Some(user_id) = req.user_id() { Ok(db - .filter(|_, player: &Player| player.has_user_id(user_id))? + .filter(|_, player: &Player| player.has_user_id(&user_id))? .next()) } else { Ok(None) } -} +} \ No newline at end of file diff --git a/geoffrey_models/src/models/parameters/add_location_params.rs b/geoffrey_models/src/models/parameters/add_location_params.rs index f7b74d9..4a0f67a 100644 --- a/geoffrey_models/src/models/parameters/add_location_params.rs +++ b/geoffrey_models/src/models/parameters/add_location_params.rs @@ -1,11 +1,25 @@ use crate::models::locations::LocationType; use crate::models::{Position, Tunnel}; use serde::{Deserialize, Serialize}; +use crate::models::player::UserID; +use crate::models::parameters::CommandRequest; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct AddLocationParams { + token: u64, + user_id: UserID, pub name: String, pub position: Position, pub loc_type: LocationType, pub tunnel: Option, } + +impl CommandRequest for AddLocationParams { + fn token(&self) -> u64 { + self.token + } + + fn user_id(&self) -> Option { + Some(self.user_id.clone()) + } +} diff --git a/geoffrey_models/src/models/parameters/find_params.rs b/geoffrey_models/src/models/parameters/find_params.rs index a03b593..9ee87f4 100644 --- a/geoffrey_models/src/models/parameters/find_params.rs +++ b/geoffrey_models/src/models/parameters/find_params.rs @@ -1,6 +1,14 @@ use serde::{Deserialize, Serialize}; +use crate::models::parameters::CommandRequest; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FindParams { + pub token: u64, pub query: String, } + +impl CommandRequest for FindParams { + fn token(&self) -> u64 { + self.token + } +} diff --git a/geoffrey_models/src/models/parameters/mod.rs b/geoffrey_models/src/models/parameters/mod.rs index 845a48e..e688488 100644 --- a/geoffrey_models/src/models/parameters/mod.rs +++ b/geoffrey_models/src/models/parameters/mod.rs @@ -5,18 +5,14 @@ pub mod register_params; use crate::models::player::{Player, UserID}; use crate::models::token::{Permissions, Token}; use crate::models::CommandLevel; -use serde::{Deserialize, Serialize}; +use serde::Serialize; +use std::fmt::Debug; +use serde::de::DeserializeOwned; -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct CommandRequest { - pub user: Option, - pub arguments: T, - pub token: u64, -} - -impl CommandRequest { - fn has_user_id(&self) -> bool { - self.user.is_some() +pub trait CommandRequest: Serialize + DeserializeOwned + Debug + Clone + Send + 'static { + fn token(&self) -> u64; + fn user_id(&self) -> Option { + None } fn check_permission( @@ -35,4 +31,4 @@ impl CommandRequest { false } } -} +} \ No newline at end of file diff --git a/geoffrey_models/src/models/parameters/register_params.rs b/geoffrey_models/src/models/parameters/register_params.rs index 0c88735..eef4b5d 100644 --- a/geoffrey_models/src/models/parameters/register_params.rs +++ b/geoffrey_models/src/models/parameters/register_params.rs @@ -1,8 +1,16 @@ use crate::models::player::UserID; use serde::{Deserialize, Serialize}; +use crate::models::parameters::CommandRequest; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct RegisterParameters { + pub token: u64, + pub new_user_id: UserID, pub username: String, - pub user_id: UserID, +} + +impl CommandRequest for RegisterParameters { + fn token(&self) -> u64 { + self.token + } }