Add user accounts, registration command, secure command valiation.

This commit is contained in:
projectmoon 2021-05-21 22:33:49 +00:00
parent a84d4fd869
commit c1ec7366e4
4 changed files with 65 additions and 2 deletions

View File

@ -33,3 +33,20 @@ impl Command for ResyncCommand {
Execution::success(message) Execution::success(message)
} }
} }
pub struct RegisterCommand(pub String);
#[async_trait]
impl Command for RegisterCommand {
fn name(&self) -> &'static str {
"register user account"
}
fn is_secure(&self) -> bool {
true
}
async fn execute(&self, ctx: &Context<'_>) -> ExecutionResult {
Execution::success("User account registered".to_string())
}
}

View File

@ -19,6 +19,9 @@ pub enum CommandError {
#[error("invalid command: {0}")] #[error("invalid command: {0}")]
InvalidCommand(String), InvalidCommand(String),
#[error("command can only be executed from encrypted direct message")]
InsecureExecution,
#[error("ignored command")] #[error("ignored command")]
IgnoredCommand, IgnoredCommand,
} }
@ -99,13 +102,33 @@ pub trait Command: Send + Sync {
fn is_secure(&self) -> bool; fn is_secure(&self) -> bool;
} }
/// Determine if we are allowed to execute this command. Currently the
/// rules are that secure commands must be executed in secure rooms
/// (encrypted + direct), and anything else can be executed where
/// ever. Later, we can add stuff like admin/regular user power
/// separation, etc.
fn execution_allowed(cmd: &(impl Command + ?Sized), ctx: &Context<'_>) -> Result<(), CommandError> {
if cmd.is_secure() {
if ctx.is_secure() {
Ok(())
} else {
Err(CommandError::InsecureExecution)
}
} else {
Ok(())
}
}
/// Attempt to execute a command, and return the content that should /// Attempt to execute a command, and return the content that should
/// go back to Matrix, if the command was executed (successfully or /// go back to Matrix, if the command was executed (successfully or
/// not). If a command is determined to be ignored, this function will /// not). If a command is determined to be ignored, this function will
/// return None, signifying that we should not send a response. /// return None, signifying that we should not send a response.
pub async fn execute_command(ctx: &Context<'_>) -> ExecutionResult { pub async fn execute_command(ctx: &Context<'_>) -> ExecutionResult {
let cmd = parser::parse_command(&ctx.message_body)?; let cmd = parser::parse_command(&ctx.message_body)?;
cmd.execute(ctx).await
match execution_allowed(cmd.as_ref(), ctx) {
Ok(_) => cmd.execute(ctx).await,
Err(e) => Err(ExecutionError(e.into())),
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -9,7 +9,7 @@ use crate::commands::{
basic_rolling::RollCommand, basic_rolling::RollCommand,
cofd::PoolRollCommand, cofd::PoolRollCommand,
cthulhu::{CthAdvanceRoll, CthRoll}, cthulhu::{CthAdvanceRoll, CthRoll},
management::ResyncCommand, management::{RegisterCommand, ResyncCommand},
misc::HelpCommand, misc::HelpCommand,
variables::{ variables::{
DeleteVariableCommand, GetAllVariablesCommand, GetVariableCommand, SetVariableCommand, DeleteVariableCommand, GetAllVariablesCommand, GetVariableCommand, SetVariableCommand,
@ -47,6 +47,10 @@ fn parse_roll(input: &str) -> Result<Box<dyn Command>, BotError> {
} }
} }
fn parse_register_command(input: &str) -> Result<Box<dyn Command>, BotError> {
Ok(Box::new(RegisterCommand(input.to_owned())))
}
fn parse_get_variable_command(input: &str) -> Result<Box<dyn Command>, BotError> { fn parse_get_variable_command(input: &str) -> Result<Box<dyn Command>, BotError> {
Ok(Box::new(GetVariableCommand(input.to_owned()))) Ok(Box::new(GetVariableCommand(input.to_owned())))
} }
@ -141,6 +145,7 @@ pub fn parse_command(input: &str) -> Result<Box<dyn Command>, BotError> {
"cthadv" | "ctharoll" => parse_cth_advancement_roll(&cmd_input), "cthadv" | "ctharoll" => parse_cth_advancement_roll(&cmd_input),
"chance" => chance_die(), "chance" => chance_die(),
"help" => help(&cmd_input), "help" => help(&cmd_input),
"register" => parse_register_command(&cmd_input),
_ => Err(CommandParsingError::UnrecognizedCommand(cmd).into()), _ => Err(CommandParsingError::UnrecognizedCommand(cmd).into()),
}, },
//All other errors passed up. //All other errors passed up.

View File

@ -0,0 +1,18 @@
use barrel::backend::Sqlite;
use barrel::{types, types::Type, Migration};
fn primary_uuid() -> Type {
types::text().unique(true).primary(true).nullable(false)
}
pub fn migration() -> String {
let mut m = Migration::new();
//Table of room ID, event ID, event timestamp
m.create_table("accounts", move |t| {
t.add_column("user_id", primary_uuid());
t.add_column("password", types::text().nullable(false));
});
m.make::<Sqlite>()
}