aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md2
-rw-r--r--src/lib.rs66
-rw-r--r--src/tests/pro.rs44
3 files changed, 110 insertions, 2 deletions
diff --git a/TODO.md b/TODO.md
index 132086c..de33f8c 100644
--- a/TODO.md
+++ b/TODO.md
@@ -5,8 +5,6 @@
- `NK_factory_reset`
- `NK_build_aes_key`
- `NK_unlock_user_password`
- - `NK_erase_hotp_slot`
- - `NK_erase_totp_slot`
- `NK_change_admin_PIN`
- `NK_change_user_PIN`
- `NK_enable_password_safe`
diff --git a/src/lib.rs b/src/lib.rs
index 117659f..8ffbf5a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1310,6 +1310,72 @@ impl AdminAuthenticatedDevice {
)
});
}
+
+ /// Erase an HOTP slot.
+ ///
+ /// # Errors
+ ///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::{CommandStatus, Device, OtpMode, OtpSlotData};
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), (CommandError)> {
+ /// let device = nitrokey::connect()?;
+ /// match device.authenticate_admin("12345678") {
+ /// Ok(admin) => {
+ /// match admin.erase_hotp_slot(1) {
+ /// CommandStatus::Success => println!("Successfully erased slot."),
+ /// CommandStatus::Error(err) => println!("Could not erase slot: {:?}", err),
+ /// }
+ /// },
+ /// Err((_, err)) => println!("Could not authenticate as admin: {:?}", err),
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ pub fn erase_hotp_slot(&self, slot: u8) -> CommandStatus {
+ let temp_password_ptr = self.temp_password.as_ptr() as *const i8;
+ unsafe { CommandStatus::from(nitrokey_sys::NK_erase_hotp_slot(slot, temp_password_ptr)) }
+ }
+
+ /// Erase a TOTP slot.
+ ///
+ /// # Errors
+ ///
+ /// - [`InvalidSlot`][] if there is no slot with the given number
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::{CommandStatus, Device, OtpMode, OtpSlotData};
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), (CommandError)> {
+ /// let device = nitrokey::connect()?;
+ /// match device.authenticate_admin("12345678") {
+ /// Ok(admin) => {
+ /// match admin.erase_totp_slot(1) {
+ /// CommandStatus::Success => println!("Successfully erased slot."),
+ /// CommandStatus::Error(err) => println!("Could not erase slot: {:?}", err),
+ /// }
+ /// },
+ /// Err((_, err)) => println!("Could not authenticate as admin: {:?}", err),
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ pub fn erase_totp_slot(&self, slot: u8) -> CommandStatus {
+ let temp_password_ptr = self.temp_password.as_ptr() as *const i8;
+ unsafe { CommandStatus::from(nitrokey_sys::NK_erase_totp_slot(slot, temp_password_ptr)) }
+ }
}
impl Device for AdminAuthenticatedDevice {}
diff --git a/src/tests/pro.rs b/src/tests/pro.rs
index a508801..a23d42a 100644
--- a/src/tests/pro.rs
+++ b/src/tests/pro.rs
@@ -136,6 +136,28 @@ fn hotp_error() {
assert_eq!(CommandError::InvalidSlot, code.unwrap_err());
}
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn hotp_erase() {
+ let admin = get_admin_test_device();
+ let config = Config::new(None, None, None, false);
+ assert_eq!(CommandStatus::Success, admin.write_config(config));
+ let slot_data = OtpSlotData::new(1, "test1", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Success, admin.write_hotp_slot(slot_data, 0));
+ let slot_data = OtpSlotData::new(2, "test2", HOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Success, admin.write_hotp_slot(slot_data, 0));
+
+ assert_eq!(CommandStatus::Success, admin.erase_hotp_slot(1));
+
+ let device = admin.device();
+ let result = device.get_hotp_slot_name(1);
+ assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err());
+ let result = device.get_hotp_code(1);
+ assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err());
+
+ assert_eq!("test2", device.get_hotp_slot_name(2).unwrap());
+}
+
fn configure_totp(admin: &AdminAuthenticatedDevice) {
let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits);
assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 30));
@@ -218,6 +240,28 @@ fn totp_error() {
#[test]
#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn totp_erase() {
+ let admin = get_admin_test_device();
+ let config = Config::new(None, None, None, false);
+ assert_eq!(CommandStatus::Success, admin.write_config(config));
+ let slot_data = OtpSlotData::new(1, "test1", TOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 0));
+ let slot_data = OtpSlotData::new(2, "test2", TOTP_SECRET, OtpMode::SixDigits);
+ assert_eq!(CommandStatus::Success, admin.write_totp_slot(slot_data, 0));
+
+ assert_eq!(CommandStatus::Success, admin.erase_totp_slot(1));
+
+ let device = admin.device();
+ let result = device.get_totp_slot_name(1);
+ assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err());
+ let result = device.get_totp_code(1);
+ assert_eq!(CommandError::SlotNotProgrammed, result.unwrap_err());
+
+ assert_eq!("test2", device.get_totp_slot_name(2).unwrap());
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
fn get_firmware_version() {
let device = get_test_device();
assert_eq!(0, device.get_major_firmware_version());