use libc;
use nitrokey_sys;
use crate::device::{Device, DeviceWrapper, Pro, Storage};
use crate::util::{
get_command_result, get_cstring, get_last_error, result_from_string, CommandError,
};
pub const SLOT_COUNT: u8 = 16;
pub struct PasswordSafe<'a> {
_device: &'a dyn Device,
}
pub trait GetPasswordSafe {
fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError>;
}
fn get_password_safe<'a>(
device: &'a dyn Device,
user_pin: &str,
) -> Result<PasswordSafe<'a>, CommandError> {
let user_pin_string = get_cstring(user_pin)?;
let result = unsafe {
get_command_result(nitrokey_sys::NK_enable_password_safe(
user_pin_string.as_ptr(),
))
};
result.map(|()| PasswordSafe { _device: device })
}
impl<'a> PasswordSafe<'a> {
pub fn get_slot_status(&self) -> Result<[bool; SLOT_COUNT as usize], CommandError> {
let status_ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_status() };
if status_ptr.is_null() {
return Err(get_last_error());
}
let status_array_ptr = status_ptr as *const [u8; SLOT_COUNT as usize];
let status_array = unsafe { *status_array_ptr };
let mut result = [false; SLOT_COUNT as usize];
for i in 0..SLOT_COUNT {
result[i as usize] = status_array[i as usize] == 1;
}
unsafe {
libc::free(status_ptr as *mut libc::c_void);
}
Ok(result)
}
pub fn get_slot_name(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_name(slot)) }
}
pub fn get_slot_login(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_login(slot)) }
}
pub fn get_slot_password(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_password(slot)) }
}
pub fn write_slot(
&self,
slot: u8,
name: &str,
login: &str,
password: &str,
) -> Result<(), CommandError> {
let name_string = get_cstring(name)?;
let login_string = get_cstring(login)?;
let password_string = get_cstring(password)?;
unsafe {
get_command_result(nitrokey_sys::NK_write_password_safe_slot(
slot,
name_string.as_ptr(),
login_string.as_ptr(),
password_string.as_ptr(),
))
}
}
pub fn erase_slot(&self, slot: u8) -> Result<(), CommandError> {
unsafe { get_command_result(nitrokey_sys::NK_erase_password_safe_slot(slot)) }
}
}
impl<'a> Drop for PasswordSafe<'a> {
fn drop(&mut self) {
}
}
impl GetPasswordSafe for Pro {
fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for Storage {
fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for DeviceWrapper {
fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}