Tests for secure commands and user DB API.

This commit is contained in:
projectmoon 2021-05-22 22:48:47 +00:00
parent 926dae57fb
commit 8c2a90e86b
3 changed files with 215 additions and 20 deletions

View File

@ -168,6 +168,7 @@ fn log_command(cmd: &(impl Command + ?Sized), ctx: &Context, result: &ExecutionR
#[cfg(test)]
mod tests {
use super::*;
use management::RegisterCommand;
use url::Url;
macro_rules! dummy_room {
@ -180,6 +181,100 @@ mod tests {
};
}
macro_rules! secure_room {
() => {
crate::context::RoomContext {
id: &matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
display_name: "displayname".to_owned(),
secure: true,
}
};
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn secure_context_secure_command_allows_execution() {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
let db = crate::db::sqlite::Database::new(db_path.path().to_str().unwrap())
.await
.unwrap();
let homeserver = Url::parse("http://example.com").unwrap();
let ctx = Context {
db: db,
matrix_client: &matrix_sdk::Client::new(homeserver).unwrap(),
room: secure_room!(),
username: "myusername",
message_body: "!notacommand",
};
let cmd = RegisterCommand("".to_owned());
assert_eq!(execution_allowed(&cmd, &ctx).is_ok(), true);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn secure_context_insecure_command_allows_execution() {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
let db = crate::db::sqlite::Database::new(db_path.path().to_str().unwrap())
.await
.unwrap();
let homeserver = Url::parse("http://example.com").unwrap();
let ctx = Context {
db: db,
matrix_client: &matrix_sdk::Client::new(homeserver).unwrap(),
room: secure_room!(),
username: "myusername",
message_body: "!notacommand",
};
let cmd = variables::GetVariableCommand("".to_owned());
assert_eq!(execution_allowed(&cmd, &ctx).is_ok(), true);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn insecure_context_insecure_command_allows_execution() {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
let db = crate::db::sqlite::Database::new(db_path.path().to_str().unwrap())
.await
.unwrap();
let homeserver = Url::parse("http://example.com").unwrap();
let ctx = Context {
db: db,
matrix_client: &matrix_sdk::Client::new(homeserver).unwrap(),
room: dummy_room!(),
username: "myusername",
message_body: "!notacommand",
};
let cmd = variables::GetVariableCommand("".to_owned());
assert_eq!(execution_allowed(&cmd, &ctx).is_ok(), true);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn insecure_context_secure_command_denies_execution() {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
let db = crate::db::sqlite::Database::new(db_path.path().to_str().unwrap())
.await
.unwrap();
let homeserver = Url::parse("http://example.com").unwrap();
let ctx = Context {
db: db,
matrix_client: &matrix_sdk::Client::new(homeserver).unwrap(),
room: dummy_room!(),
username: "myusername",
message_body: "!notacommand",
};
let cmd = RegisterCommand("".to_owned());
assert_eq!(execution_allowed(&cmd, &ctx).is_err(), true);
}
#[test]
fn command_result_extractor_creates_bubble() {
let result = Execution::success("test".to_string());
@ -205,6 +300,7 @@ mod tests {
username: "myusername",
message_body: "!notacommand",
};
let result = execute_command(&ctx).await;
assert!(result.is_err());
}

View File

@ -47,8 +47,9 @@ impl Users for Database {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::sqlite::Database;
use crate::db::DbState;
use crate::db::Users;
async fn create_db() -> Database {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
@ -62,41 +63,114 @@ mod tests {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn set_and_get_device_id() {
async fn create_and_get_user_test() {
let db = create_db().await;
db.set_device_id("device_id")
let insert_result = db
.upsert_user(&User {
username: "myuser".to_string(),
password: "abc".to_string(),
})
.await;
assert!(insert_result.is_ok());
let user = db
.get_user("myuser")
.await
.expect("Could not set device ID");
.expect("User retrieval query failed");
let device_id = db.get_device_id().await.expect("Could not get device ID");
assert!(device_id.is_some());
assert_eq!(device_id.unwrap(), "device_id");
assert!(user.is_some());
let user = user.unwrap();
assert_eq!(user.username, "myuser");
assert_eq!(user.password, "abc");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn no_device_id_set_returns_none() {
async fn can_update_user() {
let db = create_db().await;
let device_id = db.get_device_id().await.expect("Could not get device ID");
assert!(device_id.is_none());
let insert_result1 = db
.upsert_user(&User {
username: "myuser".to_string(),
password: "abc".to_string(),
})
.await;
assert!(insert_result1.is_ok());
let insert_result2 = db
.upsert_user(&User {
username: "myuser".to_string(),
password: "123".to_string(),
})
.await;
assert!(insert_result2.is_ok());
let user = db
.get_user("myuser")
.await
.expect("User retrieval query failed");
assert!(user.is_some());
let user = user.unwrap();
assert_eq!(user.username, "myuser");
assert_eq!(user.password, "123"); //From second upsert
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn can_update_device_id() {
async fn username_not_in_db_returns_none() {
let db = create_db().await;
let user = db
.get_user("does not exist")
.await
.expect("Get user query failure");
assert!(user.is_none());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn authenticate_user_is_some_with_valid_password() {
let db = create_db().await;
db.set_device_id("device_id")
let insert_result = db
.upsert_user(&User {
username: "myuser".to_string(),
password: crate::logic::hash_password("abc").expect("password hash error!"),
})
.await;
assert!(insert_result.is_ok());
let user = db
.authenticate_user("myuser", "abc")
.await
.expect("Could not set device ID");
.expect("User retrieval query failed");
db.set_device_id("device_id2")
assert!(user.is_some());
let user = user.unwrap();
assert_eq!(user.username, "myuser");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn authenticate_user_is_none_with_wrong_password() {
let db = create_db().await;
let insert_result = db
.upsert_user(&User {
username: "myuser".to_string(),
password: crate::logic::hash_password("abc").expect("password hash error!"),
})
.await;
assert!(insert_result.is_ok());
let user = db
.authenticate_user("myuser", "wrong-password")
.await
.expect("Could not set device ID");
.expect("User retrieval query failed");
let device_id = db.get_device_id().await.expect("Could not get device ID");
assert!(device_id.is_some());
assert_eq!(device_id.unwrap(), "device_id2");
assert!(user.is_none());
}
}

View File

@ -18,3 +18,28 @@ impl User {
argon2::verify_encoded(&self.password, raw_password.as_bytes()).unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_password_passes_with_correct_password() {
let user = User {
username: "myuser".to_string(),
password: crate::logic::hash_password("mypassword").expect("Password hashing error!"),
};
assert_eq!(user.verify_password("mypassword"), true);
}
#[test]
fn verify_password_fails_with_wrong_password() {
let user = User {
username: "myuser".to_string(),
password: crate::logic::hash_password("mypassword").expect("Password hashing error!"),
};
assert_eq!(user.verify_password("wrong-password"), false);
}
}