use super::*;
use crate::{
crypto::translator::KeyPairInstance, errors::KeyManagementError, unit_tests::prelude::*,
KeyManagement, KeyType, Signing,
};
use proptest::prelude::*;
use secrecy::ExposeSecret;
use strum::IntoEnumIterator;
use tempfile::{tempdir, TempDir};
fn create_file_key_manager() -> (TempDir, FileKeyManager) {
let directory = tempdir().unwrap();
let path = directory.as_ref().to_str().unwrap();
let config = FileKeyManagerConfig {
keypair_directory_path: String::from(path),
};
println!("Directory KeyPair Path: {}", config.keypair_directory_path);
(directory, FileKeyManager::new(config))
}
fn add_keypairs(count: u8, key_type: KeyType, key_manager: &mut FileKeyManager) -> Vec<String> {
std::iter::repeat_with(|| key_manager.generate_keypair(key_type).unwrap().id.value)
.take(count as usize)
.collect()
}
#[test]
fn valid_config_passes() {
let directory = tempdir().unwrap();
let path = String::from(directory.as_ref().to_str().unwrap());
let manager_config = FileKeyManagerConfig {
keypair_directory_path: path,
};
let result = manager_config.validate();
assert!(result.is_ok());
}
#[test]
fn nonexisting_path_config_fails() {
let path = String::from("/foo/bar");
let manager_config = FileKeyManagerConfig {
keypair_directory_path: path.clone(),
};
let result = manager_config.validate();
match result {
Err(KeyManagementError::InvalidDirectoryPath { path: err_path }) => {
assert_eq!(&path, &err_path)
}
_ => panic!("Expected an InvalidDirectoryPath error for: {}", &path),
}
}
#[test]
fn invalid_file_used_for_directory() {
let path = String::from("/etc/resolv.conf");
let manager_config = FileKeyManagerConfig {
keypair_directory_path: path.clone(),
};
let result = manager_config.validate();
match result {
Err(KeyManagementError::InvalidDirectoryPath { path: err_path }) => {
assert_eq!(&path, &err_path)
}
_ => panic!("Expected an InvalidDirectoryPath error for: {}", &path),
}
}
#[test]
#[ignore]
fn invalid_inaccessible_path() {
let path = String::from("/root/");
let manager_config = FileKeyManagerConfig {
keypair_directory_path: path.clone(),
};
let result = manager_config.validate();
match result {
Err(KeyManagementError::IoError { message, .. }) => {
assert!(message.contains("Could not read directory"));
assert!(message.contains(&path));
}
_ => panic!("Expected an IoError for: {}", &path),
}
}
#[test]
fn addresses_initialized_empty() {
let (_drop_me, sut) = create_file_key_manager();
let addresses = sut.get_key_ids().unwrap();
assert_eq!(addresses.len(), 0);
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(KeyType::iter().len() as u32))]
#[test]
fn addresses_generate_counts(key_type in keytype_strategy()) {
let (_drop_me, mut sut) = create_file_key_manager();
const TEST_COUNT: u8 = 4;
let mut expected_addresses = add_keypairs(TEST_COUNT, key_type, &mut sut);
expected_addresses.sort();
let addresses = sut.get_key_ids().unwrap();
let mut addresses: Vec<String> = addresses
.into_iter()
.map(|address| address.value)
.collect();
addresses.sort();
prop_assert_eq!(addresses.len() as u8, TEST_COUNT);
prop_assert_eq!(&expected_addresses, &addresses);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(KeyType::iter().len() as u32))]
#[test]
fn has_key(key_type in keytype_strategy()) {
let (_drop_me, mut sut) = create_file_key_manager();
let in_manager_generated = sut.generate_keypair(key_type).unwrap();
let generated = KeyPairInstance::generate(key_type).unwrap();
let in_manager_result = sut.has_key(in_manager_generated.as_ref()).unwrap();
let generated_result = sut.has_key(&generated.identifier()).unwrap();
prop_assert!(in_manager_result);
prop_assert!(!generated_result);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(KeyType::iter().len() as u32))]
#[test]
fn import_address(key_type in keytype_strategy()) {
let (_drop_me, mut sut) = create_file_key_manager();
let generated = KeyPairInstance::generate(key_type).unwrap();
let addresses = sut.get_key_ids().unwrap();
prop_assert_eq!(0, addresses.len());
sut.import_keypair(generated.to_secret().unwrap(), key_type).unwrap();
let addresses = sut.get_key_ids().unwrap();
prop_assert_eq!(addresses.len() as u8, 1);
prop_assert_eq!(generated.identifier(), addresses[0].clone());
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(KeyType::iter().len() as u32))]
#[test]
fn import_derived_key_address((secret, _path) in get_dev_derived_key_strategy(),
key_type in sign_capable_keytype_strategy()) {
let (_drop_me, mut sut) = create_file_key_manager();
let from_secret = KeyPairInstance::from_secret(Secret::new(secret.clone()), key_type);
let from_secret = from_secret.unwrap();
let addresses = sut.get_key_ids().unwrap();
prop_assert_eq!(0, addresses.len());
sut.import_keypair(Secret::new(secret.clone()), key_type).unwrap();
let addresses = sut.get_key_ids().unwrap();
prop_assert_eq!(addresses.len() as u8, 1);
prop_assert_eq!(&from_secret.identifier(), &addresses[0]);
let from_secret_string = from_secret.to_secret().unwrap();
prop_assert_eq!(&&secret, &from_secret_string.expose_secret());
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(20))]
#[test]
fn signing_occurs_from_file_key_manager_interface(
key_type in sign_capable_keytype_strategy(),
message in proptest::string::bytes_regex(".+").unwrap()
) {
let (_drop_me, mut sut) = create_file_key_manager();
let generated_address = sut.generate_keypair(key_type).unwrap();
let signed = sut.sign(generated_address.as_ref(), message.as_slice()).unwrap();
prop_assert_eq!(!signed.as_ref().as_ref().is_empty(), true);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(KeyType::iter().len() as u32))]
#[test]
fn sign_invalid_address(key_type in keytype_strategy()) {
let (_drop_me, sut) = create_file_key_manager();
let invalid_address = KeyIdentifier {
value: "../../5Hh9Gq21Ns4Knd6CjzjMymK6HeW9yYfxdMfhMoDyA8geHVbJ".into(),
key_type
};
let result = sut.sign(&invalid_address, b"Some Message");
prop_assert!(result.is_err());
}
}
#[test]
fn sign_non_existing_key() {
let (_drop_me, sut) = create_file_key_manager();
let generated = KeyPairInstance::generate(KeyType::SubstrateSr25519).unwrap();
let generated_address = generated.identifier();
let result = sut.sign(&generated_address, b"A Message that won't be signed");
match result {
Err(KeyManagementError::AddressNotFound { address }) => {
assert_eq!(&generated_address.value, &address)
}
_ => panic!(
"Expected an AddressNotFound for: {}",
&generated_address.value
),
}
}