From a04a8707c78bf8d035931837910bf9ce90f45678 Mon Sep 17 00:00:00 2001 From: beac0n Date: Wed, 10 Jul 2024 23:03:23 +0200 Subject: [PATCH] add tests --- rustfmt.toml | 2 +- src/bin/client.rs | 4 +- src/blocklist.rs | 2 +- src/client.rs | 8 +- src/commander.rs | 2 +- src/server.rs | 6 +- tests/blocklist_test.rs | 70 ++++++++++++++ tests/client_send_test.rs | 41 ++++++-- tests/commander_test.rs | 2 +- tests/integration_test.rs | 197 +++++++++++++++++++++++++------------- 10 files changed, 245 insertions(+), 89 deletions(-) create mode 100644 tests/blocklist_test.rs diff --git a/rustfmt.toml b/rustfmt.toml index 41e2da3..f98aab5 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -70,7 +70,7 @@ required_version = "1.7.0" unstable_features = false disable_all_formatting = false skip_children = false -hide_parse_errors = false +show_parse_errors = true error_on_line_overflow = false error_on_unformatted = false ignore = [] diff --git a/src/bin/client.rs b/src/bin/client.rs index a523991..c43f46a 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -5,7 +5,7 @@ use std::str; use clap::{Parser, Subcommand}; use ruroco::client::{gen, send}; -use ruroco::common::init_logger; +use ruroco::common::{init_logger, time}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -78,6 +78,6 @@ fn main() -> Result<(), String> { address, command, deadline, - } => send(private_pem_path, address, command, deadline), + } => send(private_pem_path, address, command, deadline, time()?), }; } diff --git a/src/blocklist.rs b/src/blocklist.rs index 9a905d6..53401a4 100644 --- a/src/blocklist.rs +++ b/src/blocklist.rs @@ -2,8 +2,8 @@ use std::fs; use std::path::PathBuf; use log::error; +use serde::ser::{SerializeSeq, Serializer}; use serde::{Deserialize, Serialize}; -use serde::ser::{Serializer, SerializeSeq}; use crate::common::get_blocklist_path; diff --git a/src/client.rs b/src/client.rs index 469b018..0a05a57 100644 --- a/src/client.rs +++ b/src/client.rs @@ -8,7 +8,7 @@ use openssl::pkey::Private; use openssl::rsa::Rsa; use openssl::version::version; -use crate::common::{PADDING_SIZE, RSA_PADDING, time}; +use crate::common::{PADDING_SIZE, RSA_PADDING}; fn pem_load_err(err: I, val: E) -> String { format!("Could not load {val:?}: {err}") @@ -23,11 +23,12 @@ pub fn send( address: String, command: String, deadline: u16, + now: u128, ) -> Result<(), String> { info!("Connecting to udp://{address}, loading PEM from {pem_path:?}, using {} ...", version()); let rsa = get_rsa_private(&pem_path)?; - let data_to_encrypt = get_data_to_encrypt(&command, &rsa, deadline)?; + let data_to_encrypt = get_data_to_encrypt(&command, &rsa, deadline, now)?; let encrypted_data = encrypt_data(&data_to_encrypt, &rsa)?; // create UDP socket and send the encrypted data to the specified address @@ -57,11 +58,12 @@ fn get_data_to_encrypt( command: &str, rsa: &Rsa, deadline: u16, + now: u128, ) -> Result, String> { // collect data to encrypt: now-timestamp + command + random data -> all as bytes let mut data_to_encrypt = Vec::new(); - let timestamp = time()? + (u128::from(deadline) * 1_000_000_000); + let timestamp = now + (u128::from(deadline) * 1_000_000_000); let timestamp_bytes = timestamp.to_le_bytes().to_vec(); let timestamp_len = timestamp_bytes.len(); data_to_encrypt.extend(timestamp_bytes); diff --git a/src/commander.rs b/src/commander.rs index 95451b0..7f5170d 100644 --- a/src/commander.rs +++ b/src/commander.rs @@ -1,4 +1,3 @@ -use std::{fs, str}; use std::collections::HashMap; use std::fs::Permissions; use std::io::Read; @@ -6,6 +5,7 @@ use std::os::unix::fs::{chown, PermissionsExt}; use std::os::unix::net::{UnixListener, UnixStream}; use std::path::PathBuf; use std::process::Command; +use std::{fs, str}; use log::{error, info, warn}; use users::{get_group_by_name, get_user_by_name}; diff --git a/src/server.rs b/src/server.rs index 76eea93..297bb81 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,9 +1,9 @@ -use std::{env, fs, str}; use std::io::Write; use std::net::{SocketAddr, UdpSocket}; use std::os::fd::{FromRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::path::PathBuf; +use std::{env, fs, str}; use log::{error, info}; use openssl::error::ErrorStack; @@ -12,7 +12,7 @@ use openssl::rsa::Rsa; use openssl::version::version; use crate::blocklist::Blocklist; -use crate::common::{get_socket_path, RSA_PADDING, time}; +use crate::common::{get_socket_path, time, RSA_PADDING}; pub struct Server { rsa: Rsa, @@ -158,8 +158,6 @@ impl Server { "Successfully validated data - now {} is before deadline {}", data.now_ns, data.deadline_ns ); - // TODO: blacklist data.deadline_ns until data.deadline_ns == data.now_ns - // TODO: remove all blacklisted timestamps that are now too old in the next validate call self.send_command(&data.command_name); self.update_block_list(&data); } diff --git a/tests/blocklist_test.rs b/tests/blocklist_test.rs new file mode 100644 index 0000000..7cc0772 --- /dev/null +++ b/tests/blocklist_test.rs @@ -0,0 +1,70 @@ +#[cfg(test)] +mod tests { + use std::{env, fs}; + + use ruroco::blocklist::Blocklist; + use ruroco::common::get_blocklist_path; + + fn create_blocklist() -> Blocklist { + let config_dir = &env::current_dir().unwrap(); + let _ = fs::remove_file(get_blocklist_path(config_dir)); + Blocklist::create(config_dir) + } + + #[test] + fn test_add() { + let mut blocklist = create_blocklist(); + let number: u128 = 42; + let another_number: u128 = 1337; + + blocklist.add(number); + assert_eq!(blocklist.get().len(), 1); + assert_eq!(blocklist.get().first().unwrap().clone(), number); + + blocklist.add(another_number); + assert_eq!(blocklist.get().len(), 2); + assert_eq!(blocklist.get().get(0).unwrap().clone(), number); + assert_eq!(blocklist.get().get(1).unwrap().clone(), another_number); + } + + #[test] + fn test_clean() { + let mut blocklist = create_blocklist(); + + blocklist.add(21); + blocklist.add(42); + blocklist.add(63); + blocklist.add(84); + blocklist.add(105); + + assert_eq!(blocklist.get().len(), 5); + + blocklist.clean(63); + assert_eq!(blocklist.get().len(), 2); + assert_eq!(blocklist.get().get(0).unwrap().clone(), 84); + assert_eq!(blocklist.get().get(1).unwrap().clone(), 105); + } + + #[test] + fn test_save() { + let mut blocklist = create_blocklist(); + + blocklist.add(42); + blocklist.save(); + blocklist.add(1337); + + let other_blocklist = Blocklist::create(&env::current_dir().unwrap()); + assert_eq!(other_blocklist.get().len(), 1); + assert_eq!(other_blocklist.get().first().unwrap().clone(), 42); + } + + #[test] + fn test_is_blocked() { + let mut blocklist = create_blocklist(); + + blocklist.add(42); + + assert!(blocklist.is_blocked(42)); + assert!(!blocklist.is_blocked(1337)); + } +} diff --git a/tests/client_send_test.rs b/tests/client_send_test.rs index 8097c19..ba5d1bd 100644 --- a/tests/client_send_test.rs +++ b/tests/client_send_test.rs @@ -10,6 +10,7 @@ mod tests { use rand::distributions::{Alphanumeric, DistString}; use ruroco::client::gen; + use ruroco::common::time; use super::*; @@ -22,7 +23,13 @@ mod tests { fn test_send_no_such_file() { let pem_file_name = gen_file_name(".pem"); let pem_path = PathBuf::from(&pem_file_name); - let result = send(pem_path, String::from("127.0.0.1:1234"), String::from("default"), 5); + let result = send( + pem_path, + String::from("127.0.0.1:1234"), + String::from("default"), + 5, + time().unwrap(), + ); assert_eq!( result.unwrap_err().to_string(), @@ -36,7 +43,13 @@ mod tests { File::create(&pem_file_name).unwrap(); let pem_path = PathBuf::from(&pem_file_name); - let result = send(pem_path, String::from("127.0.0.1:1234"), String::from("default"), 5); + let result = send( + pem_path, + String::from("127.0.0.1:1234"), + String::from("default"), + 5, + time().unwrap(), + ); let _ = fs::remove_file(&pem_file_name); @@ -56,7 +69,8 @@ mod tests { gen(private_pem_path.clone(), public_pem_path, 1024).unwrap(); let address = String::from("127.0.0.1:asd"); - let result = send(private_pem_path, address.clone(), String::from("default"), 5); + let result = + send(private_pem_path, address.clone(), String::from("default"), 5, time().unwrap()); let _ = fs::remove_file(&private_file); let _ = fs::remove_file(&public_file); @@ -77,7 +91,8 @@ mod tests { gen(private_pem_path.clone(), public_pem_path, 1024).unwrap(); let address = String::from("999.999.999.999:9999"); - let result = send(private_pem_path, address.clone(), String::from("default"), 5); + let result = + send(private_pem_path, address.clone(), String::from("default"), 5, time().unwrap()); let _ = fs::remove_file(&private_file); let _ = fs::remove_file(&public_file); @@ -100,8 +115,13 @@ mod tests { let public_pem_path = PathBuf::from(&public_file); gen(private_pem_path.clone(), public_pem_path, 1024).unwrap(); - let result = - send(private_pem_path, String::from("127.0.0.1:1234"), "default".repeat(24), 5); + let result = send( + private_pem_path, + String::from("127.0.0.1:1234"), + "default".repeat(24), + 5, + time().unwrap(), + ); let _ = fs::remove_file(&private_file); let _ = fs::remove_file(&public_file); @@ -121,8 +141,13 @@ mod tests { let public_pem_path = PathBuf::from(&public_file); gen(private_pem_path.clone(), public_pem_path, 1024).unwrap(); - let result = - send(private_pem_path, String::from("127.0.0.1:1234"), String::from("default"), 5); + let result = send( + private_pem_path, + String::from("127.0.0.1:1234"), + String::from("default"), + 5, + time().unwrap(), + ); let _ = fs::remove_file(&private_file); let _ = fs::remove_file(&public_file); diff --git a/tests/commander_test.rs b/tests/commander_test.rs index d361d01..bd6b451 100644 --- a/tests/commander_test.rs +++ b/tests/commander_test.rs @@ -1,9 +1,9 @@ #[cfg(test)] mod tests { - use std::{fs, thread}; use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::time::Duration; + use std::{fs, thread}; use rand::distributions::{Alphanumeric, DistString}; diff --git a/tests/integration_test.rs b/tests/integration_test.rs index df937a8..f9e9f02 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,9 +1,9 @@ #[cfg(test)] mod tests { - use std::{env, fs, thread}; use std::collections::HashMap; - use std::path::{Path, PathBuf}; + use std::path::PathBuf; use std::time::Duration; + use std::{env, fs, thread}; use rand::distributions::{Alphanumeric, DistString}; use rand::Rng; @@ -11,61 +11,140 @@ mod tests { use ruroco::blocklist::Blocklist; use ruroco::client::{gen, send}; use ruroco::commander::Commander; - use ruroco::common::{get_blocklist_path, get_socket_path, init_logger}; + use ruroco::common::{get_blocklist_path, get_socket_path, init_logger, time}; use ruroco::server::Server; - fn gen_file_name(suffix: &str) -> String { - let rand_str = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); - return format!("{rand_str}{suffix}"); + struct TestData { + test_file_path: PathBuf, + socket_path: PathBuf, + blocklist_path: PathBuf, + public_pem_path: PathBuf, + private_pem_path: PathBuf, + server_address: String, } - #[test] - fn test_integration_key_size_1024() { - run_integration_test(1024); + impl TestData { + fn create() -> TestData { + TestData { + test_file_path: PathBuf::from(gen_file_name(".test")), + socket_path: get_socket_path(&env::current_dir().unwrap()), + blocklist_path: get_blocklist_path(&env::current_dir().unwrap()), + public_pem_path: PathBuf::from(gen_file_name(".pem")), + private_pem_path: get_private_pem_path(), + server_address: format!("127.0.0.1:{}", rand::thread_rng().gen_range(1024..65535)), + } + } } #[test] - fn test_integration_key_size_2048() { - run_integration_test(2048); + fn test_too_late() { + let test_data: TestData = TestData::create(); + + run_client_gen(&test_data); + run_server(&test_data); + run_commander(&test_data); + + run_client_send(&test_data, 0, time().unwrap()); + assert_file_paths(&test_data, false, false); } #[test] - fn test_integration_key_size_4096() { - run_integration_test(4096); + fn test_is_blocked() { + init_logger(); + + let test_data: TestData = TestData::create(); + + run_client_gen(&test_data); + run_server(&test_data); + run_commander(&test_data); + + let now = time().unwrap(); + run_client_send(&test_data, 5, now); + let _ = fs::remove_file(&test_data.test_file_path); + + run_client_send(&test_data, 5, now); + assert_file_paths(&test_data, false, true); } #[test] - fn test_integration_key_size_8192() { - run_integration_test(8192); + fn test_integration_test() { + init_logger(); + + let test_data: TestData = TestData::create(); + + run_client_gen(&test_data); + run_server(&test_data); + run_commander(&test_data); + + run_client_send(&test_data, 1, time().unwrap()); + let blocked_list_0 = get_blocked_list(); + + run_client_send(&test_data, 5, time().unwrap()); + let blocked_list_1 = get_blocked_list(); + + assert_file_paths(&test_data, true, true); + + assert_eq!(blocked_list_0.len(), 1); + assert_eq!(blocked_list_1.len(), 1); + assert_ne!(blocked_list_0.first(), blocked_list_1.first()); } - fn run_integration_test(key_size: u32) { - init_logger(); + fn run_client_gen(file_paths: &TestData) { + let key_size = 1024; - let server_address = format!("127.0.0.1:{}", rand::thread_rng().gen_range(1024..65535)); + gen(file_paths.private_pem_path.clone(), file_paths.public_pem_path.clone(), key_size) + .unwrap(); + } - let curr_dir = &env::current_dir().unwrap(); - let test_filename = gen_file_name(".test"); - let socket_path = get_socket_path(curr_dir); - let blocklist_path = get_blocklist_path(curr_dir); - let public_pem_path = PathBuf::from(gen_file_name(".pem")); - let mut private_pem_path = env::current_dir().unwrap(); - private_pem_path.push("tests"); - private_pem_path.push(gen_file_name(".pem")); + fn assert_file_paths( + test_data: &TestData, + with_test_file_exists: bool, + with_block_list_exists: bool, + ) { + let test_file_exists = test_data.test_file_path.exists(); + let private_exists = test_data.private_pem_path.exists(); + let public_exists = test_data.public_pem_path.exists(); + let socket_exists = test_data.socket_path.exists(); + let blocklist_exists = test_data.blocklist_path.exists(); + + let _ = fs::remove_file(&test_data.test_file_path); + let _ = fs::remove_file(&test_data.private_pem_path); + let _ = fs::remove_file(&test_data.public_pem_path); + let _ = fs::remove_file(&test_data.socket_path); + let _ = fs::remove_file(&test_data.blocklist_path); + + assert_eq!(test_file_exists, with_test_file_exists); + assert!(private_exists); + assert!(public_exists); + assert!(socket_exists); + assert_eq!(blocklist_exists, with_block_list_exists); + } - gen(private_pem_path.clone(), public_pem_path.clone(), key_size).unwrap(); + fn gen_file_name(suffix: &str) -> String { + let rand_str = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); + return format!("{rand_str}{suffix}"); + } - let server_address_for_server = server_address.clone(); + fn get_blocked_list() -> Vec { + let blocklist = Blocklist::create(&env::current_dir().unwrap()); + blocklist.get().clone() + } - thread::spawn(move || { - Server::create(env::current_dir().unwrap(), server_address_for_server) - .expect("could not create server") - .run() - .expect("server terminated") - }); + fn run_client_send(test_data: &TestData, deadline: u16, now: u128) { + send( + test_data.private_pem_path.clone(), + test_data.server_address.to_string(), + String::from("default"), + deadline, + now, + ) + .unwrap(); + thread::sleep(Duration::from_secs(1)); // wait for commands to be executed + } + fn run_commander(test_data: &TestData) { let mut config = HashMap::new(); - config.insert(String::from("default"), format!("touch {}", &test_filename)); + config.insert(String::from("default"), format!("touch {:?}", &test_data.test_file_path)); thread::spawn(move || { Commander::create( @@ -77,41 +156,23 @@ mod tests { .run() .expect("commander terminated") }); + } - send(private_pem_path.clone(), server_address.to_string(), String::from("default"), 1) - .unwrap(); - thread::sleep(Duration::from_secs(1)); // wait for commands to be executed - let blocklist = Blocklist::create(curr_dir); - let blocked_list_0 = blocklist.get(); - - let _ = fs::remove_file(&test_filename); + fn run_server(test_data: &TestData) { + let server_address_clone = test_data.server_address.clone(); - send(private_pem_path.clone(), server_address.to_string(), String::from("default"), 5) - .unwrap(); - thread::sleep(Duration::from_secs(1)); // wait for commands to be executed - let blocklist = Blocklist::create(curr_dir); - let blocked_list_1 = blocklist.get(); - - let start_test_exists = Path::new(&test_filename).exists(); - let private_exists = private_pem_path.exists(); - let public_exists = public_pem_path.exists(); - let socket_exists = socket_path.exists(); - let blocklist_exists = blocklist_path.exists(); - - let _ = fs::remove_file(&test_filename); - let _ = fs::remove_file(&private_pem_path); - let _ = fs::remove_file(&public_pem_path); - let _ = fs::remove_file(socket_path); - let _ = fs::remove_file(blocklist_path); - - assert!(start_test_exists); - assert!(private_exists); - assert!(public_exists); - assert!(socket_exists); - assert!(blocklist_exists); + thread::spawn(move || { + Server::create(env::current_dir().unwrap(), server_address_clone) + .expect("could not create server") + .run() + .expect("server terminated") + }); + } - assert_eq!(blocked_list_0.len(), 1); - assert_eq!(blocked_list_1.len(), 1); - assert_ne!(blocked_list_0.first(), blocked_list_1.first()); + fn get_private_pem_path() -> PathBuf { + let mut private_pem_path = env::current_dir().unwrap(); + private_pem_path.push("tests"); + private_pem_path.push(gen_file_name(".pem")); + private_pem_path } }