mod util;
use std::ffi::CStr;
use libc::{c_int, c_void, free};
use nitrokey::{
CommandError, Device, Error, GetPasswordSafe, LibraryError, PasswordSafe, PasswordSlot,
DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN,
};
use nitrokey_sys;
use nitrokey_test::test as test_device;
fn get_slot_name_direct(slot: u8) -> Result<String, Error> {
let ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_name(slot) };
if ptr.is_null() {
return Err(Error::UnexpectedError("null pointer".to_owned()));
}
let s = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
unsafe { free(ptr as *mut c_void) };
match s.is_empty() {
true => {
let error = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int;
match error {
0 => Ok(s),
other => Err(Error::from(other)),
}
}
false => Ok(s),
}
}
fn get_pws<'a, T>(device: &mut T) -> PasswordSafe<'_, 'a>
where
T: Device<'a>,
{
unwrap_ok!(device.get_password_safe(DEFAULT_USER_PIN))
}
#[test_device]
fn enable(device: DeviceWrapper) {
let mut device = device;
assert_cmd_err!(
CommandError::WrongPassword,
device.get_password_safe(&(DEFAULT_USER_PIN.to_owned() + "123"))
);
assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN));
assert_cmd_err!(
CommandError::WrongPassword,
device.get_password_safe(DEFAULT_ADMIN_PIN)
);
assert_any_ok!(device.get_password_safe(DEFAULT_USER_PIN));
}
#[test_device]
fn drop(device: DeviceWrapper) {
let mut device = device;
{
let mut pws = get_pws(&mut device);
assert_ok!((), pws.write_slot(1, "name", "login", "password"));
let slot = unwrap_ok!(pws.get_slot_unchecked(1));
assert_ok!("name".to_string(), slot.get_name());
let result = get_slot_name_direct(1);
assert_ok!(String::from("name"), result);
}
let result = get_slot_name_direct(1);
assert_ok!(String::from("name"), result);
assert_ok!((), device.lock());
let result = get_slot_name_direct(1);
assert_cmd_err!(CommandError::NotAuthorized, result);
}
#[test_device]
fn get_status(device: DeviceWrapper) {
fn get_pws_status(pws: &PasswordSafe<'_, '_>) -> Vec<Option<u8>> {
unwrap_ok!(pws.get_slots())
.iter()
.map(|opt| opt.as_ref().map(PasswordSlot::index))
.collect()
}
let mut device = device;
let mut pws = get_pws(&mut device);
let slot_count = pws.get_slot_count();
for i in 0..slot_count {
assert_ok!((), pws.erase_slot(i));
}
assert_eq!(vec![None; slot_count.into()], get_pws_status(&pws));
assert_ok!((), pws.write_slot(1, "name", "login", "password"));
for (i, slot) in get_pws_status(&pws).into_iter().enumerate() {
if i == 1 {
assert_eq!(Some(1), slot);
} else {
assert_eq!(None, slot);
}
}
for i in 0..slot_count {
assert_ok!((), pws.write_slot(i, "name", "login", "password"));
}
assert_eq!(
(0..slot_count).map(Some).collect::<Vec<_>>(),
get_pws_status(&pws)
);
}
#[test_device]
fn get_data(device: DeviceWrapper) {
let mut device = device;
let mut pws = get_pws(&mut device);
assert_ok!((), pws.write_slot(1, "name", "login", "password"));
let slot = unwrap_ok!(pws.get_slot_unchecked(1));
assert_ok!("name".to_string(), slot.get_name());
assert_ok!("login".to_string(), slot.get_login());
assert_ok!("password".to_string(), slot.get_password());
drop(slot);
assert_ok!((), pws.erase_slot(1));
assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot(1));
let slot = unwrap_ok!(pws.get_slot_unchecked(1));
assert_ok!(String::new(), slot.get_name());
assert_ok!(String::new(), slot.get_login());
assert_ok!(String::new(), slot.get_password());
drop(slot);
let name = "with å";
let login = "pär@test.com";
let password = "'i3lJc[09?I:,[u7dWz9";
assert_ok!((), pws.write_slot(1, name, login, password));
let slot = unwrap_ok!(pws.get_slot_unchecked(1));
assert_ok!(name.to_string(), slot.get_name());
assert_ok!(login.to_string(), slot.get_login());
assert_ok!(password.to_string(), slot.get_password());
drop(slot);
let slot_count = pws.get_slot_count();
assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot(slot_count));
assert_lib_err!(
LibraryError::InvalidSlot,
pws.get_slot_unchecked(slot_count)
);
}
#[test_device]
fn write(device: DeviceWrapper) {
let mut device = device;
let mut pws = get_pws(&mut device);
assert_lib_err!(
LibraryError::InvalidSlot,
pws.write_slot(pws.get_slot_count(), "name", "login", "password")
);
assert_ok!((), pws.write_slot(0, "", "login", "password"));
let slot = unwrap_ok!(pws.get_slot_unchecked(0));
assert_ok!(String::new(), slot.get_name());
assert_ok!(String::from("login"), slot.get_login());
assert_ok!(String::from("password"), slot.get_password());
assert_ok!((), pws.write_slot(0, "name", "", "password"));
let slot = unwrap_ok!(pws.get_slot_unchecked(0));
assert_ok!(String::from("name"), slot.get_name());
assert_ok!(String::new(), slot.get_login());
assert_ok!(String::from("password"), slot.get_password());
assert_ok!((), pws.write_slot(0, "name", "login", ""));
let slot = unwrap_ok!(pws.get_slot_unchecked(0));
assert_ok!(String::from("name"), slot.get_name());
assert_ok!(String::from("login"), slot.get_login());
assert_ok!(String::new(), slot.get_password());
}
#[test_device]
fn erase(device: DeviceWrapper) {
let mut device = device;
let mut pws = get_pws(&mut device);
assert_lib_err!(
LibraryError::InvalidSlot,
pws.erase_slot(pws.get_slot_count())
);
assert_ok!((), pws.write_slot(0, "name", "login", "password"));
assert_ok!((), pws.erase_slot(0));
assert_ok!((), pws.erase_slot(0));
assert_cmd_err!(CommandError::SlotNotProgrammed, pws.get_slot(0));
}