aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2019-07-14 18:04:32 -0700
committerDaniel Mueller <deso@posteo.net>2019-07-14 18:04:32 -0700
commitec9dddc17d7466ec44fbfd08e71546b8c0ba9b1b (patch)
tree802f9a136725439eb081ab28e5dd52f2dcf60d27
parent019b1bb66d83bd904df3e545654f16e70e677ce8 (diff)
downloadnitrocli-ec9dddc17d7466ec44fbfd08e71546b8c0ba9b1b.tar.gz
nitrocli-ec9dddc17d7466ec44fbfd08e71546b8c0ba9b1b.tar.bz2
Introduce with_*device functionality
The upcoming nitrokey 0.4 release changes the way a device handle can be acquired, requiring a manager instance for doing so in an attempt to prevent users from opening multiple sessions (which is not something that libnitrokey supports). A straight integration of the reworked API surface into our program would severely complicate the architecture because of the additional requirement of keeping a manager object around while a device is being used. To make the program more amenable to those changes in nitrokey, this patch reworks the way we interact with a device handle: instead of passing the device object around we pass in the functionality making use of it in the form of a function. In more concrete terms, instead of retrieving a device handle via get_device() we now have a with_device() function that takes care of opening the device and then passing it to a user-provided function.
-rw-r--r--nitrocli/src/commands.rs533
1 files changed, 284 insertions, 249 deletions
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs
index f473db7..6285c90 100644
--- a/nitrocli/src/commands.rs
+++ b/nitrocli/src/commands.rs
@@ -57,21 +57,29 @@ fn set_log_level(ctx: &mut args::ExecCtx<'_>) {
nitrokey::set_log_level(log_lvl);
}
-/// Connect to any Nitrokey device and return it.
-fn get_device(ctx: &mut args::ExecCtx<'_>) -> Result<nitrokey::DeviceWrapper> {
+/// Connect to any Nitrokey device and do something with it.
+fn with_device<F>(ctx: &mut args::ExecCtx<'_>, op: F) -> Result<()>
+where
+ F: FnOnce(&mut args::ExecCtx<'_>, nitrokey::DeviceWrapper) -> Result<()>,
+{
set_log_level(ctx);
- match ctx.model {
+ let device = match ctx.model {
Some(model) => nitrokey::connect_model(model.into()).map_err(|_| {
let error = format!("Nitrokey {} device not found", model.as_user_facing_str());
Error::Error(error)
- }),
- None => nitrokey::connect().map_err(|_| Error::from("Nitrokey device not found")),
- }
+ })?,
+ None => nitrokey::connect().map_err(|_| Error::from("Nitrokey device not found"))?,
+ };
+
+ op(ctx, device)
}
-/// Connect to a Nitrokey Storage device and return it.
-fn get_storage_device(ctx: &mut args::ExecCtx<'_>) -> Result<nitrokey::Storage> {
+/// Connect to a Nitrokey Storage device and do something with it.
+fn with_storage_device<F>(ctx: &mut args::ExecCtx<'_>, op: F) -> Result<()>
+where
+ F: FnOnce(&mut args::ExecCtx<'_>, nitrokey::Storage) -> Result<()>,
+{
set_log_level(ctx);
if let Some(model) = ctx.model {
@@ -82,7 +90,9 @@ fn get_storage_device(ctx: &mut args::ExecCtx<'_>) -> Result<nitrokey::Storage>
}
}
- nitrokey::Storage::connect().map_err(|_| Error::from("Nitrokey Storage device not found"))
+ let device =
+ nitrokey::Storage::connect().map_err(|_| Error::from("Nitrokey Storage device not found"))?;
+ op(ctx, device)
}
/// Open the password safe on the given device.
@@ -332,34 +342,36 @@ fn print_status(
/// Inquire the status of the nitrokey.
pub fn status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_device(ctx)?;
- let model = match device {
- nitrokey::DeviceWrapper::Pro(_) => "Pro",
- nitrokey::DeviceWrapper::Storage(_) => "Storage",
- };
- print_status(ctx, model, &device)
+ with_device(ctx, |ctx, device| {
+ let model = match device {
+ nitrokey::DeviceWrapper::Pro(_) => "Pro",
+ nitrokey::DeviceWrapper::Storage(_) => "Storage",
+ };
+ print_status(ctx, model, &device)
+ })
}
/// Perform a factory reset.
pub fn reset(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_device(ctx)?;
- let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
-
- // To force the user to enter the admin PIN before performing a
- // factory reset, we clear the pinentry cache for the admin PIN.
- pinentry::clear(&pin_entry)?;
-
- try_with_pin(ctx, &pin_entry, "Factory reset failed", |pin| {
- device.factory_reset(&pin)?;
- // Work around for a timing issue between factory_reset and
- // build_aes_key, see
- // https://github.com/Nitrokey/nitrokey-storage-firmware/issues/80
- thread::sleep(time::Duration::from_secs(3));
- // Another work around for spurious WrongPassword returns of
- // build_aes_key after a factory reset on Pro devices.
- // https://github.com/Nitrokey/nitrokey-pro-firmware/issues/57
- let _ = device.get_user_retry_count();
- device.build_aes_key(NITROKEY_DEFAULT_ADMIN_PIN)
+ with_device(ctx, |ctx, device| {
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
+
+ // To force the user to enter the admin PIN before performing a
+ // factory reset, we clear the pinentry cache for the admin PIN.
+ pinentry::clear(&pin_entry)?;
+
+ try_with_pin(ctx, &pin_entry, "Factory reset failed", |pin| {
+ device.factory_reset(&pin)?;
+ // Work around for a timing issue between factory_reset and
+ // build_aes_key, see
+ // https://github.com/Nitrokey/nitrokey-storage-firmware/issues/80
+ thread::sleep(time::Duration::from_secs(3));
+ // Another work around for spurious WrongPassword returns of
+ // build_aes_key after a factory reset on Pro devices.
+ // https://github.com/Nitrokey/nitrokey-pro-firmware/issues/57
+ let _ = device.get_user_retry_count();
+ device.build_aes_key(NITROKEY_DEFAULT_ADMIN_PIN)
+ })
})
}
@@ -368,99 +380,107 @@ pub fn unencrypted_set(
ctx: &mut args::ExecCtx<'_>,
mode: args::UnencryptedVolumeMode,
) -> Result<()> {
- let device = get_storage_device(ctx)?;
- let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
- let mode = match mode {
- args::UnencryptedVolumeMode::ReadWrite => nitrokey::VolumeMode::ReadWrite,
- args::UnencryptedVolumeMode::ReadOnly => nitrokey::VolumeMode::ReadOnly,
- };
+ with_storage_device(ctx, |ctx, device| {
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
+ let mode = match mode {
+ args::UnencryptedVolumeMode::ReadWrite => nitrokey::VolumeMode::ReadWrite,
+ args::UnencryptedVolumeMode::ReadOnly => nitrokey::VolumeMode::ReadOnly,
+ };
- // The unencrypted volume may reconnect, so be sure to flush caches to
- // disk.
- unsafe { sync() };
+ // The unencrypted volume may reconnect, so be sure to flush caches to
+ // disk.
+ unsafe { sync() };
- try_with_pin(
- ctx,
- &pin_entry,
- "Changing unencrypted volume mode failed",
- |pin| device.set_unencrypted_volume_mode(&pin, mode),
- )
+ try_with_pin(
+ ctx,
+ &pin_entry,
+ "Changing unencrypted volume mode failed",
+ |pin| device.set_unencrypted_volume_mode(&pin, mode),
+ )
+ })
}
/// Open the encrypted volume on the Nitrokey.
pub fn encrypted_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_storage_device(ctx)?;
- let pin_entry = pinentry::PinEntry::from(pinentry::PinType::User, &device)?;
+ with_storage_device(ctx, |ctx, device| {
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::User, &device)?;
- // We may forcefully close a hidden volume, if active, so be sure to
- // flush caches to disk.
- unsafe { sync() };
+ // We may forcefully close a hidden volume, if active, so be sure to
+ // flush caches to disk.
+ unsafe { sync() };
- try_with_pin(ctx, &pin_entry, "Opening encrypted volume failed", |pin| {
- device.enable_encrypted_volume(&pin)
+ try_with_pin(ctx, &pin_entry, "Opening encrypted volume failed", |pin| {
+ device.enable_encrypted_volume(&pin)
+ })
})
}
/// Close the previously opened encrypted volume.
pub fn encrypted_close(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- // Flush all filesystem caches to disk. We are mostly interested in
- // making sure that the encrypted volume on the Nitrokey we are
- // about to close is not closed while not all data was written to
- // it.
- unsafe { sync() };
+ with_storage_device(ctx, |_ctx, device| {
+ // Flush all filesystem caches to disk. We are mostly interested in
+ // making sure that the encrypted volume on the Nitrokey we are
+ // about to close is not closed while not all data was written to
+ // it.
+ unsafe { sync() };
- get_storage_device(ctx)?
- .disable_encrypted_volume()
- .map_err(|err| get_error("Closing encrypted volume failed", err))
+ device
+ .disable_encrypted_volume()
+ .map_err(|err| get_error("Closing encrypted volume failed", err))
+ })
}
/// Create a hidden volume.
pub fn hidden_create(ctx: &mut args::ExecCtx<'_>, slot: u8, start: u8, end: u8) -> Result<()> {
- let device = get_storage_device(ctx)?;
- let pwd_entry = pinentry::PwdEntry::from(&device)?;
- let pwd = if let Some(pwd) = &ctx.password {
- pwd
- .to_str()
- .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
- .map(ToOwned::to_owned)
- } else {
- pinentry::choose(ctx, &pwd_entry)
- }?;
+ with_storage_device(ctx, |ctx, device| {
+ let pwd_entry = pinentry::PwdEntry::from(&device)?;
+ let pwd = if let Some(pwd) = &ctx.password {
+ pwd
+ .to_str()
+ .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
+ .map(ToOwned::to_owned)
+ } else {
+ pinentry::choose(ctx, &pwd_entry)
+ }?;
- device
- .create_hidden_volume(slot, start, end, &pwd)
- .map_err(|err| get_error("Creating hidden volume failed", err))
+ device
+ .create_hidden_volume(slot, start, end, &pwd)
+ .map_err(|err| get_error("Creating hidden volume failed", err))
+ })
}
/// Open a hidden volume.
pub fn hidden_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_storage_device(ctx)?;
- let pwd_entry = pinentry::PwdEntry::from(&device)?;
- let pwd = if let Some(pwd) = &ctx.password {
- pwd
- .to_str()
- .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
- .map(ToOwned::to_owned)
- } else {
- pinentry::inquire(ctx, &pwd_entry, pinentry::Mode::Query, None)
- }?;
+ with_storage_device(ctx, |ctx, device| {
+ let pwd_entry = pinentry::PwdEntry::from(&device)?;
+ let pwd = if let Some(pwd) = &ctx.password {
+ pwd
+ .to_str()
+ .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found"))
+ .map(ToOwned::to_owned)
+ } else {
+ pinentry::inquire(ctx, &pwd_entry, pinentry::Mode::Query, None)
+ }?;
- // We may forcefully close an encrypted volume, if active, so be sure
- // to flush caches to disk.
- unsafe { sync() };
+ // We may forcefully close an encrypted volume, if active, so be sure
+ // to flush caches to disk.
+ unsafe { sync() };
- device
- .enable_hidden_volume(&pwd)
- .map_err(|err| get_error("Opening hidden volume failed", err))
+ device
+ .enable_hidden_volume(&pwd)
+ .map_err(|err| get_error("Opening hidden volume failed", err))
+ })
}
/// Close a previously opened hidden volume.
pub fn hidden_close(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- unsafe { sync() };
+ with_storage_device(ctx, |_ctx, device| {
+ unsafe { sync() };
- get_storage_device(ctx)?
- .disable_hidden_volume()
- .map_err(|err| get_error("Closing hidden volume failed", err))
+ device
+ .disable_hidden_volume()
+ .map_err(|err| get_error("Closing hidden volume failed", err))
+ })
}
/// Return a String representation of the given Option.
@@ -473,22 +493,24 @@ fn format_option<T: fmt::Display>(option: Option<T>) -> String {
/// Read the Nitrokey configuration.
pub fn config_get(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let config = get_device(ctx)?
- .get_config()
- .map_err(|err| get_error("Could not get configuration", err))?;
- println!(
- ctx,
- r#"Config:
+ with_device(ctx, |ctx, device| {
+ let config = device
+ .get_config()
+ .map_err(|err| get_error("Could not get configuration", err))?;
+ println!(
+ ctx,
+ r#"Config:
numlock binding: {nl}
capslock binding: {cl}
scrollock binding: {sl}
require user PIN for OTP: {otp}"#,
- nl = format_option(config.numlock),
- cl = format_option(config.capslock),
- sl = format_option(config.scrollock),
- otp = config.user_password,
- )?;
- Ok(())
+ nl = format_option(config.numlock),
+ cl = format_option(config.capslock),
+ sl = format_option(config.scrollock),
+ otp = config.user_password,
+ )?;
+ Ok(())
+ })
}
/// Write the Nitrokey configuration.
@@ -499,27 +521,30 @@ pub fn config_set(
scrollock: args::ConfigOption<u8>,
user_password: Option<bool>,
) -> Result<()> {
- let device = get_device(ctx)?;
- let device = authenticate_admin(ctx, device)?;
- let config = device
- .get_config()
- .map_err(|err| get_error("Could not get configuration", err))?;
- let config = nitrokey::Config {
- numlock: numlock.or(config.numlock),
- capslock: capslock.or(config.capslock),
- scrollock: scrollock.or(config.scrollock),
- user_password: user_password.unwrap_or(config.user_password),
- };
- device
- .write_config(config)
- .map_err(|err| get_error("Could not set configuration", err))
+ with_device(ctx, |ctx, device| {
+ let device = authenticate_admin(ctx, device)?;
+ let config = device
+ .get_config()
+ .map_err(|err| get_error("Could not get configuration", err))?;
+ let config = nitrokey::Config {
+ numlock: numlock.or(config.numlock),
+ capslock: capslock.or(config.capslock),
+ scrollock: scrollock.or(config.scrollock),
+ user_password: user_password.unwrap_or(config.user_password),
+ };
+ device
+ .write_config(config)
+ .map_err(|err| get_error("Could not set configuration", err))
+ })
}
/// Lock the Nitrokey device.
pub fn lock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- get_device(ctx)?
- .lock()
- .map_err(|err| get_error("Could not lock the device", err))
+ with_device(ctx, |_ctx, device| {
+ device
+ .lock()
+ .map_err(|err| get_error("Could not lock the device", err))
+ })
}
fn get_otp<T: GenerateOtp>(slot: u8, algorithm: args::OtpAlgorithm, device: &T) -> Result<String> {
@@ -544,29 +569,30 @@ pub fn otp_get(
algorithm: args::OtpAlgorithm,
time: Option<u64>,
) -> Result<()> {
- let device = get_device(ctx)?;
- if algorithm == args::OtpAlgorithm::Totp {
- device
- .set_time(
- match time {
- Some(time) => time,
- None => get_unix_timestamp()?,
- },
- true,
- )
- .map_err(|err| get_error("Could not set time", err))?;
- }
- let config = device
- .get_config()
- .map_err(|err| get_error("Could not get device configuration", err))?;
- let otp = if config.user_password {
- let user = authenticate_user(ctx, device)?;
- get_otp(slot, algorithm, &user)
- } else {
- get_otp(slot, algorithm, &device)
- }?;
- println!(ctx, "{}", otp)?;
- Ok(())
+ with_device(ctx, |ctx, device| {
+ if algorithm == args::OtpAlgorithm::Totp {
+ device
+ .set_time(
+ match time {
+ Some(time) => time,
+ None => get_unix_timestamp()?,
+ },
+ true,
+ )
+ .map_err(|err| get_error("Could not set time", err))?;
+ }
+ let config = device
+ .get_config()
+ .map_err(|err| get_error("Could not get device configuration", err))?;
+ let otp = if config.user_password {
+ let user = authenticate_user(ctx, device)?;
+ get_otp(slot, algorithm, &user)
+ } else {
+ get_otp(slot, algorithm, &device)
+ }?;
+ println!(ctx, "{}", otp)?;
+ Ok(())
+ })
}
/// Format a byte vector as a hex string.
@@ -609,20 +635,21 @@ pub fn otp_set(
time_window: u16,
secret_format: args::OtpSecretFormat,
) -> Result<()> {
- let secret = match secret_format {
- args::OtpSecretFormat::Ascii => prepare_ascii_secret(&data.secret)?,
- args::OtpSecretFormat::Base32 => prepare_base32_secret(&data.secret)?,
- args::OtpSecretFormat::Hex => data.secret,
- };
- let data = nitrokey::OtpSlotData { secret, ..data };
- let device = get_device(ctx)?;
- let device = authenticate_admin(ctx, 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(())
+ with_device(ctx, |ctx, device| {
+ let secret = match secret_format {
+ args::OtpSecretFormat::Ascii => prepare_ascii_secret(&data.secret)?,
+ args::OtpSecretFormat::Base32 => prepare_base32_secret(&data.secret)?,
+ args::OtpSecretFormat::Hex => data.secret,
+ };
+ let data = nitrokey::OtpSlotData { secret, ..data };
+ let device = authenticate_admin(ctx, 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(())
+ })
}
/// Clear an OTP slot.
@@ -631,14 +658,15 @@ pub fn otp_clear(
slot: u8,
algorithm: args::OtpAlgorithm,
) -> Result<()> {
- let device = get_device(ctx)?;
- let device = authenticate_admin(ctx, device)?;
- match algorithm {
- args::OtpAlgorithm::Hotp => device.erase_hotp_slot(slot),
- args::OtpAlgorithm::Totp => device.erase_totp_slot(slot),
- }
- .map_err(|err| get_error("Could not clear OTP slot", err))?;
- Ok(())
+ with_device(ctx, |ctx, device| {
+ let device = authenticate_admin(ctx, device)?;
+ match algorithm {
+ args::OtpAlgorithm::Hotp => device.erase_hotp_slot(slot),
+ args::OtpAlgorithm::Totp => device.erase_totp_slot(slot),
+ }
+ .map_err(|err| get_error("Could not clear OTP slot", err))?;
+ Ok(())
+ })
}
fn print_otp_status(
@@ -677,23 +705,24 @@ fn print_otp_status(
/// Print the status of the OTP slots.
pub fn otp_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
- let device = get_device(ctx)?;
- println!(ctx, "alg\tslot\tname")?;
- print_otp_status(ctx, args::OtpAlgorithm::Hotp, &device, all)?;
- print_otp_status(ctx, args::OtpAlgorithm::Totp, &device, all)?;
- Ok(())
+ with_device(ctx, |ctx, device| {
+ println!(ctx, "alg\tslot\tname")?;
+ print_otp_status(ctx, args::OtpAlgorithm::Hotp, &device, all)?;
+ print_otp_status(ctx, args::OtpAlgorithm::Totp, &device, all)?;
+ Ok(())
+ })
}
/// Clear the PIN stored by various operations.
pub fn pin_clear(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_device(ctx)?;
-
- pinentry::clear(&pinentry::PinEntry::from(
- pinentry::PinType::Admin,
- &device,
- )?)?;
- pinentry::clear(&pinentry::PinEntry::from(pinentry::PinType::User, &device)?)?;
- Ok(())
+ with_device(ctx, |_ctx, device| {
+ pinentry::clear(&pinentry::PinEntry::from(
+ pinentry::PinType::Admin,
+ &device,
+ )?)?;
+ pinentry::clear(&pinentry::PinEntry::from(pinentry::PinType::User, &device)?)?;
+ Ok(())
+ })
}
/// Choose a PIN of the given type.
@@ -734,39 +763,41 @@ fn choose_pin(
/// Change a PIN.
pub fn pin_set(ctx: &mut args::ExecCtx<'_>, pin_type: pinentry::PinType) -> Result<()> {
- let device = get_device(ctx)?;
- let pin_entry = pinentry::PinEntry::from(pin_type, &device)?;
- let new_pin = choose_pin(ctx, &pin_entry, true)?;
-
- try_with_pin(
- ctx,
- &pin_entry,
- "Could not change the PIN",
- |current_pin| match pin_type {
- pinentry::PinType::Admin => device.change_admin_pin(&current_pin, &new_pin),
- pinentry::PinType::User => device.change_user_pin(&current_pin, &new_pin),
- },
- )?;
+ with_device(ctx, |ctx, device| {
+ let pin_entry = pinentry::PinEntry::from(pin_type, &device)?;
+ let new_pin = choose_pin(ctx, &pin_entry, true)?;
+
+ try_with_pin(
+ ctx,
+ &pin_entry,
+ "Could not change the PIN",
+ |current_pin| match pin_type {
+ pinentry::PinType::Admin => device.change_admin_pin(&current_pin, &new_pin),
+ pinentry::PinType::User => device.change_user_pin(&current_pin, &new_pin),
+ },
+ )?;
- // We just changed the PIN but confirmed the action with the old PIN,
- // which may have caused it to be cached. Since it no longer applies,
- // make sure to evict the corresponding entry from the cache.
- pinentry::clear(&pin_entry)
+ // We just changed the PIN but confirmed the action with the old PIN,
+ // which may have caused it to be cached. Since it no longer applies,
+ // make sure to evict the corresponding entry from the cache.
+ pinentry::clear(&pin_entry)
+ })
}
/// Unblock and reset the user PIN.
pub fn pin_unblock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
- let device = get_device(ctx)?;
- let pin_entry = pinentry::PinEntry::from(pinentry::PinType::User, &device)?;
- let user_pin = choose_pin(ctx, &pin_entry, false)?;
- let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
-
- try_with_pin(
- ctx,
- &pin_entry,
- "Could not unblock the user PIN",
- |admin_pin| device.unlock_user_pin(&admin_pin, &user_pin),
- )
+ with_device(ctx, |ctx, device| {
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::User, &device)?;
+ let user_pin = choose_pin(ctx, &pin_entry, false)?;
+ let pin_entry = pinentry::PinEntry::from(pinentry::PinType::Admin, &device)?;
+
+ try_with_pin(
+ ctx,
+ &pin_entry,
+ "Could not unblock the user PIN",
+ |admin_pin| device.unlock_user_pin(&admin_pin, &user_pin),
+ )
+ })
}
fn print_pws_data(
@@ -810,21 +841,22 @@ pub fn pws_get(
show_password: bool,
quiet: bool,
) -> Result<()> {
- let device = get_device(ctx)?;
- let pws = get_password_safe(ctx, &device)?;
- check_slot(&pws, slot)?;
+ with_device(ctx, |ctx, device| {
+ let pws = get_password_safe(ctx, &device)?;
+ check_slot(&pws, slot)?;
- let show_all = !show_name && !show_login && !show_password;
- if show_all || show_name {
- print_pws_data(ctx, "name: ", pws.get_slot_name(slot), quiet)?;
- }
- if show_all || show_login {
- print_pws_data(ctx, "login: ", pws.get_slot_login(slot), quiet)?;
- }
- if show_all || show_password {
- print_pws_data(ctx, "password:", pws.get_slot_password(slot), quiet)?;
- }
- Ok(())
+ let show_all = !show_name && !show_login && !show_password;
+ if show_all || show_name {
+ print_pws_data(ctx, "name: ", pws.get_slot_name(slot), quiet)?;
+ }
+ if show_all || show_login {
+ print_pws_data(ctx, "login: ", pws.get_slot_login(slot), quiet)?;
+ }
+ if show_all || show_password {
+ print_pws_data(ctx, "password:", pws.get_slot_password(slot), quiet)?;
+ }
+ Ok(())
+ })
}
/// Write a PWS slot.
@@ -835,20 +867,22 @@ pub fn pws_set(
login: &str,
password: &str,
) -> Result<()> {
- let device = get_device(ctx)?;
- let pws = get_password_safe(ctx, &device)?;
- pws
- .write_slot(slot, name, login, password)
- .map_err(|err| get_error("Could not write PWS slot", err))
+ with_device(ctx, |ctx, device| {
+ let pws = get_password_safe(ctx, &device)?;
+ pws
+ .write_slot(slot, name, login, password)
+ .map_err(|err| get_error("Could not write PWS slot", err))
+ })
}
/// Clear a PWS slot.
pub fn pws_clear(ctx: &mut args::ExecCtx<'_>, slot: u8) -> Result<()> {
- let device = get_device(ctx)?;
- let pws = get_password_safe(ctx, &device)?;
- pws
- .erase_slot(slot)
- .map_err(|err| get_error("Could not clear PWS slot", err))
+ with_device(ctx, |ctx, device| {
+ let pws = get_password_safe(ctx, &device)?;
+ pws
+ .erase_slot(slot)
+ .map_err(|err| get_error("Could not clear PWS slot", err))
+ })
}
fn print_pws_slot(
@@ -874,20 +908,21 @@ fn print_pws_slot(
/// Print the status of all PWS slots.
pub fn pws_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
- let device = get_device(ctx)?;
- let pws = get_password_safe(ctx, &device)?;
- let slots = pws
- .get_slot_status()
- .map_err(|err| get_error("Could not read PWS slot status", err))?;
- println!(ctx, "slot\tname")?;
- for (i, &value) in slots
- .into_iter()
- .enumerate()
- .filter(|(_, &value)| all || value)
- {
- print_pws_slot(ctx, &pws, i, value)?;
- }
- Ok(())
+ with_device(ctx, |ctx, device| {
+ let pws = get_password_safe(ctx, &device)?;
+ let slots = pws
+ .get_slot_status()
+ .map_err(|err| get_error("Could not read PWS slot status", err))?;
+ println!(ctx, "slot\tname")?;
+ for (i, &value) in slots
+ .into_iter()
+ .enumerate()
+ .filter(|(_, &value)| all || value)
+ {
+ print_pws_slot(ctx, &pws, i, value)?;
+ }
+ Ok(())
+ })
}
#[cfg(test)]