diff options
Diffstat (limited to 'nitrocli/src/commands.rs')
-rw-r--r-- | nitrocli/src/commands.rs | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index a82734e..8dc8c42 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -19,6 +19,7 @@ use std::result; +use nitrokey::ConfigureOtp; use nitrokey::Device; use nitrokey::GenerateOtp; @@ -73,7 +74,6 @@ where } /// Authenticate the given device with the admin PIN. -#[allow(unused)] fn authenticate_admin<T>(device: T) -> Result<nitrokey::Admin<T>> where T: Device, @@ -276,3 +276,68 @@ pub fn otp_get(slot: u8, algorithm: args::OtpAlgorithm) -> Result<()> { println!("{}", otp); Ok(()) } + +/// Prepare an ASCII secret string for libnitrokey. +/// +/// libnitrokey expects secrets as hexadecimal strings. This function transforms an ASCII string +/// into a hexadecimal string or returns an error if the given string contains non-ASCII +/// characters. +fn prepare_secret(secret: &str) -> Result<String> { + if secret.is_ascii() { + Ok( + secret + .as_bytes() + .iter() + .map(|c| format!("{:x}", c)) + .collect::<Vec<String>>() + .join(""), + ) + } else { + Err(Error::Error( + "The given secret is not an ASCII string despite --ascii being set".to_string(), + )) + } +} + +/// Configure a one-time password slot on the Nitrokey device. +pub fn otp_set( + data: nitrokey::OtpSlotData, + algorithm: args::OtpAlgorithm, + counter: u64, + time_window: u16, + ascii: bool, +) -> Result<()> { + let secret = if ascii { + prepare_secret(&data.secret)? + } else { + data.secret + }; + let data = nitrokey::OtpSlotData { secret, ..data }; + let device = authenticate_admin(get_device()?)?; + match algorithm { + args::OtpAlgorithm::Hotp => device.write_hotp_slot(data, counter), + args::OtpAlgorithm::Totp => device.write_totp_slot(data, time_window), + } + .map_err(|err| get_error("Could not write OTP slot", &err))?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn prepare_secret_ascii() { + let result = prepare_secret("12345678901234567890"); + assert_eq!( + "3132333435363738393031323334353637383930".to_string(), + result.unwrap() + ); + } + + #[test] + fn prepare_secret_non_ascii() { + let result = prepare_secret("Österreich"); + assert!(result.is_err()); + } +} |