aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2019-01-05 18:36:33 -0800
committerDaniel Mueller <deso@posteo.net>2019-01-05 18:36:33 -0800
commitb750c4b13272908a51b85072008554c344b25016 (patch)
treece1512eacb1bfc0d507c01f171534fb7d66c3241
parent1d1cc940f47c41637adea5c5a1e5d3c80807f9d7 (diff)
downloadnitrocli-b750c4b13272908a51b85072008554c344b25016.tar.gz
nitrocli-b750c4b13272908a51b85072008554c344b25016.tar.bz2
Work with mutable ExecCtx references
So far we have used a read-only reference to a command execution context and passed that through to all consumers. However, with upcoming changes we would will need to provide data that can be modified. This change adjusts all function signatures accordingly. Also, because the ExecCtx will contain references itself in the future, this change already introduces a lifetime for the struct, as that also requires signature adjustments.
-rw-r--r--nitrocli/src/args.rs67
-rw-r--r--nitrocli/src/commands.rs44
2 files changed, 58 insertions, 53 deletions
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs
index b5d4e81..e45c4b9 100644
--- a/nitrocli/src/args.rs
+++ b/nitrocli/src/args.rs
@@ -63,9 +63,10 @@ impl str::FromStr for DeviceModel {
/// A command execution context that captures additional data pertaining
/// the command execution.
#[derive(Debug)]
-pub struct ExecCtx {
+pub struct ExecCtx<'io> {
pub model: Option<DeviceModel>,
pub verbosity: u64,
+ data: std::marker::PhantomData<&'io u64>,
}
/// A top-level command for nitrocli.
@@ -82,7 +83,7 @@ pub enum Command {
impl Command {
/// Execute this command with the given arguments.
- pub fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ pub fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
Command::Config => config(ctx, args),
Command::Lock => lock(ctx, args),
@@ -137,7 +138,7 @@ enum ConfigCommand {
}
impl ConfigCommand {
- fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
ConfigCommand::Get => config_get(ctx, args),
ConfigCommand::Set => config_set(ctx, args),
@@ -214,7 +215,7 @@ enum OtpCommand {
}
impl OtpCommand {
- fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
OtpCommand::Clear => otp_clear(ctx, args),
OtpCommand::Get => otp_get(ctx, args),
@@ -366,7 +367,7 @@ enum PinCommand {
}
impl PinCommand {
- fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
PinCommand::Clear => pin_clear(args),
PinCommand::Set => pin_set(ctx, args),
@@ -411,7 +412,7 @@ enum PwsCommand {
}
impl PwsCommand {
- fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
PwsCommand::Clear => pws_clear(ctx, args),
PwsCommand::Get => pws_get(ctx, args),
@@ -459,7 +460,7 @@ fn parse(parser: &argparse::ArgumentParser<'_>, args: Vec<String>) -> Result<()>
}
/// Inquire the status of the nitrokey.
-fn status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Prints the status of the connected Nitrokey device");
parse(&parser, args)?;
@@ -475,7 +476,7 @@ enum StorageCommand {
}
impl StorageCommand {
- fn execute(&self, ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+ fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
match *self {
StorageCommand::Close => storage_close(ctx, args),
StorageCommand::Open => storage_open(ctx, args),
@@ -512,7 +513,7 @@ impl str::FromStr for StorageCommand {
}
/// Execute a storage subcommand.
-fn storage(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn storage(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut subcommand = StorageCommand::Open;
let mut subargs = vec![];
let mut parser = argparse::ArgumentParser::new();
@@ -536,7 +537,7 @@ fn storage(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Open the encrypted volume on the nitrokey.
-fn storage_open(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn storage_open(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Opens the encrypted volume on a Nitrokey Storage");
parse(&parser, args)?;
@@ -545,7 +546,7 @@ fn storage_open(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Close the previously opened encrypted volume.
-fn storage_close(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn storage_close(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Closes the encrypted volume on a Nitrokey Storage");
parse(&parser, args)?;
@@ -554,7 +555,7 @@ fn storage_close(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Print the status of the nitrokey's storage.
-fn storage_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn storage_status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Prints the status of the Nitrokey's storage");
parse(&parser, args)?;
@@ -563,7 +564,7 @@ fn storage_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Execute a config subcommand.
-fn config(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn config(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut subcommand = ConfigCommand::Get;
let mut subargs = vec![];
let mut parser = argparse::ArgumentParser::new();
@@ -587,7 +588,7 @@ fn config(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Read the Nitrokey configuration.
-fn config_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn config_get(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Prints the Nitrokey configuration");
parse(&parser, args)?;
@@ -596,7 +597,7 @@ fn config_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Write the Nitrokey configuration.
-fn config_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn config_set(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut numlock = None;
let mut no_numlock = false;
let mut capslock = None;
@@ -664,7 +665,7 @@ fn config_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Lock the Nitrokey.
-fn lock(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn lock(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Locks the connected Nitrokey device");
parse(&parser, args)?;
@@ -673,7 +674,7 @@ fn lock(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Execute an OTP subcommand.
-fn otp(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn otp(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut subcommand = OtpCommand::Get;
let mut subargs = vec![];
let mut parser = argparse::ArgumentParser::new();
@@ -697,7 +698,7 @@ fn otp(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Generate a one-time password on the Nitrokey device.
-fn otp_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn otp_get(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut algorithm = OtpAlgorithm::Totp;
let mut time: Option<u64> = None;
@@ -725,7 +726,7 @@ fn otp_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Configure a one-time password slot on the Nitrokey device.
-pub fn otp_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut algorithm = OtpAlgorithm::Totp;
let mut name = "".to_owned();
@@ -809,7 +810,7 @@ pub fn otp_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Clear an OTP slot.
-fn otp_clear(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn otp_clear(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut algorithm = OtpAlgorithm::Totp;
let mut parser = argparse::ArgumentParser::new();
@@ -831,7 +832,7 @@ fn otp_clear(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Print the status of the OTP slots.
-fn otp_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn otp_status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut all = false;
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Prints the status of the OTP slots");
@@ -847,7 +848,7 @@ fn otp_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Execute a PIN subcommand.
-fn pin(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pin(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut subcommand = PinCommand::Clear;
let mut subargs = vec![];
let mut parser = argparse::ArgumentParser::new();
@@ -880,7 +881,7 @@ fn pin_clear(args: Vec<String>) -> Result<()> {
}
/// Change a PIN.
-fn pin_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pin_set(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut pintype = pinentry::PinType::User;
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Changes a PIN");
@@ -896,7 +897,7 @@ fn pin_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Unblock and reset the user PIN.
-fn pin_unblock(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pin_unblock(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Unblocks and resets the user PIN");
parse(&parser, args)?;
@@ -905,7 +906,7 @@ fn pin_unblock(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Execute a PWS subcommand.
-fn pws(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pws(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut subcommand = PwsCommand::Get;
let mut subargs = vec![];
let mut parser = argparse::ArgumentParser::new();
@@ -929,7 +930,7 @@ fn pws(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Access a slot of the password safe on the Nitrokey.
-fn pws_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pws_get(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut name = false;
let mut login = false;
@@ -969,7 +970,7 @@ fn pws_get(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Set a slot of the password safe on the Nitrokey.
-fn pws_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pws_set(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut name = String::new();
let mut login = String::new();
@@ -1003,7 +1004,7 @@ fn pws_set(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Clear a PWS slot.
-fn pws_clear(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pws_clear(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut slot: u8 = 0;
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Clears a password safe slot");
@@ -1019,7 +1020,7 @@ fn pws_clear(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
}
/// Print the status of the PWS slots.
-fn pws_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
+fn pws_status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> {
let mut all = false;
let mut parser = argparse::ArgumentParser::new();
parser.set_description("Prints the status of the PWS slots");
@@ -1036,7 +1037,7 @@ fn pws_status(ctx: &ExecCtx, args: Vec<String>) -> Result<()> {
/// Parse the command-line arguments and return the selected command and
/// the remaining arguments for the command.
-fn parse_arguments(args: Vec<String>) -> Result<(Command, ExecCtx, Vec<String>)> {
+fn parse_arguments<'io>(args: Vec<String>) -> Result<(Command, ExecCtx<'io>, Vec<String>)> {
let mut model: Option<DeviceModel> = None;
let mut verbosity = 0;
let mut command = Command::Status;
@@ -1069,12 +1070,12 @@ fn parse_arguments(args: Vec<String>) -> Result<(Command, ExecCtx, Vec<String>)>
subargs.insert(0, format!("nitrocli {}", command));
- let ctx = ExecCtx { model, verbosity };
+ let ctx = ExecCtx { model, verbosity, data: Default::default() };
Ok((command, ctx, subargs))
}
/// Parse the command-line arguments and execute the selected command.
pub fn handle_arguments(args: Vec<String>) -> Result<()> {
- let (command, ctx, args) = parse_arguments(args)?;
- command.execute(&ctx, args)
+ let (command, mut ctx, args) = parse_arguments(args)?;
+ command.execute(&mut ctx, args)
}
diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs
index 289c257..6c83c29 100644
--- a/nitrocli/src/commands.rs
+++ b/nitrocli/src/commands.rs
@@ -39,7 +39,7 @@ fn get_error(msg: &str, err: nitrokey::CommandError) -> Error {
}
/// Set `libnitrokey`'s log level based on the execution context's verbosity.
-fn set_log_level(ctx: &args::ExecCtx) {
+fn set_log_level(ctx: &mut args::ExecCtx<'_>) {
let log_lvl = match ctx.verbosity {
// The error log level is what libnitrokey uses by default. As such,
// there is no harm in us setting that as well when the user did not
@@ -55,7 +55,7 @@ fn set_log_level(ctx: &args::ExecCtx) {
}
/// Connect to any Nitrokey device and return it.
-fn get_device(ctx: &args::ExecCtx) -> Result<nitrokey::DeviceWrapper> {
+fn get_device(ctx: &mut args::ExecCtx<'_>) -> Result<nitrokey::DeviceWrapper> {
set_log_level(ctx);
match ctx.model {
@@ -71,7 +71,7 @@ fn get_device(ctx: &args::ExecCtx) -> Result<nitrokey::DeviceWrapper> {
}
/// Connect to a Nitrokey Storage device and return it.
-fn get_storage_device(ctx: &args::ExecCtx) -> Result<nitrokey::Storage> {
+fn get_storage_device(ctx: &mut args::ExecCtx<'_>) -> Result<nitrokey::Storage> {
set_log_level(ctx);
if let Some(model) = ctx.model {
@@ -254,7 +254,7 @@ fn print_status(model: &'static str, device: &nitrokey::DeviceWrapper) -> Result
}
/// Inquire the status of the nitrokey.
-pub fn status(ctx: &args::ExecCtx) -> Result<()> {
+pub fn status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
let device = get_device(ctx)?;
let model = match device {
nitrokey::DeviceWrapper::Pro(_) => "Pro",
@@ -264,7 +264,7 @@ pub fn status(ctx: &args::ExecCtx) -> Result<()> {
}
/// Open the encrypted volume on the nitrokey.
-pub fn storage_open(ctx: &args::ExecCtx) -> Result<()> {
+pub fn storage_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
let device = get_storage_device(ctx)?;
try_with_passphrase(
pinentry::PinType::User,
@@ -274,7 +274,7 @@ pub fn storage_open(ctx: &args::ExecCtx) -> Result<()> {
}
/// Close the previously opened encrypted volume.
-pub fn storage_close(ctx: &args::ExecCtx) -> Result<()> {
+pub fn storage_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
@@ -315,7 +315,7 @@ fn print_storage_status(status: &nitrokey::StorageStatus) {
}
/// Connect to and pretty print the status of a Nitrokey Storage.
-pub fn storage_status(ctx: &args::ExecCtx) -> Result<()> {
+pub fn storage_status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
let device = get_storage_device(ctx)?;
let status = device
.get_status()
@@ -334,7 +334,7 @@ fn format_option<T: fmt::Display>(option: Option<T>) -> String {
}
/// Read the Nitrokey configuration.
-pub fn config_get(ctx: &args::ExecCtx) -> Result<()> {
+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))?;
@@ -354,7 +354,7 @@ pub fn config_get(ctx: &args::ExecCtx) -> Result<()> {
/// Write the Nitrokey configuration.
pub fn config_set(
- ctx: &args::ExecCtx,
+ ctx: &mut args::ExecCtx<'_>,
numlock: args::ConfigOption<u8>,
capslock: args::ConfigOption<u8>,
scrollock: args::ConfigOption<u8>,
@@ -376,7 +376,7 @@ pub fn config_set(
}
/// Lock the Nitrokey device.
-pub fn lock(ctx: &args::ExecCtx) -> Result<()> {
+pub fn lock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
get_device(ctx)?
.lock()
.map_err(|err| get_error("Getting Storage status failed", err))
@@ -403,7 +403,7 @@ fn get_unix_timestamp() -> Result<u64> {
/// Generate a one-time password on the Nitrokey device.
pub fn otp_get(
- ctx: &args::ExecCtx,
+ ctx: &mut args::ExecCtx<'_>,
slot: u8,
algorithm: args::OtpAlgorithm,
time: Option<u64>,
@@ -466,7 +466,7 @@ fn prepare_base32_secret(secret: &str) -> Result<String> {
/// Configure a one-time password slot on the Nitrokey device.
pub fn otp_set(
- ctx: &args::ExecCtx,
+ ctx: &mut args::ExecCtx<'_>,
data: nitrokey::OtpSlotData,
algorithm: args::OtpAlgorithm,
counter: u64,
@@ -489,7 +489,11 @@ pub fn otp_set(
}
/// Clear an OTP slot.
-pub fn otp_clear(ctx: &args::ExecCtx, slot: u8, algorithm: args::OtpAlgorithm) -> Result<()> {
+pub fn otp_clear(
+ ctx: &mut args::ExecCtx<'_>,
+ slot: u8,
+ algorithm: args::OtpAlgorithm,
+) -> Result<()> {
let device = authenticate_admin(get_device(ctx)?)?;
match algorithm {
args::OtpAlgorithm::Hotp => device.erase_hotp_slot(slot),
@@ -535,7 +539,7 @@ fn print_otp_status(
}
/// Print the status of the OTP slots.
-pub fn otp_status(ctx: &args::ExecCtx, all: bool) -> Result<()> {
+pub fn otp_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
let device = get_device(ctx)?;
println!("alg\tslot\tname");
print_otp_status(args::OtpAlgorithm::Hotp, &device, all)?;
@@ -584,7 +588,7 @@ fn choose_pin(pintype: pinentry::PinType) -> Result<String> {
}
/// Change a PIN.
-pub fn pin_set(ctx: &args::ExecCtx, pintype: pinentry::PinType) -> Result<()> {
+pub fn pin_set(ctx: &mut args::ExecCtx<'_>, pintype: pinentry::PinType) -> Result<()> {
let device = get_device(ctx)?;
let new_pin = choose_pin(pintype)?;
try_with_passphrase(
@@ -598,7 +602,7 @@ pub fn pin_set(ctx: &args::ExecCtx, pintype: pinentry::PinType) -> Result<()> {
}
/// Unblock and reset the user PIN.
-pub fn pin_unblock(ctx: &args::ExecCtx) -> Result<()> {
+pub fn pin_unblock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
let device = get_device(ctx)?;
let user_pin = choose_pin(pinentry::PinType::User)?;
try_with_passphrase(
@@ -624,7 +628,7 @@ fn print_pws_data(
/// Read a PWS slot.
pub fn pws_get(
- ctx: &args::ExecCtx,
+ ctx: &mut args::ExecCtx<'_>,
slot: u8,
show_name: bool,
show_login: bool,
@@ -648,7 +652,7 @@ pub fn pws_get(
/// Write a PWS slot.
pub fn pws_set(
- ctx: &args::ExecCtx,
+ ctx: &mut args::ExecCtx<'_>,
slot: u8,
name: &str,
login: &str,
@@ -662,7 +666,7 @@ pub fn pws_set(
}
/// Clear a PWS slot.
-pub fn pws_clear(ctx: &args::ExecCtx, slot: u8) -> Result<()> {
+pub fn pws_clear(ctx: &mut args::ExecCtx<'_>, slot: u8) -> Result<()> {
let device = get_device(ctx)?;
let pws = get_password_safe(&device)?;
pws
@@ -687,7 +691,7 @@ fn print_pws_slot(pws: &nitrokey::PasswordSafe<'_>, slot: usize, programmed: boo
}
/// Print the status of all PWS slots.
-pub fn pws_status(ctx: &args::ExecCtx, all: bool) -> Result<()> {
+pub fn pws_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
let device = get_device(ctx)?;
let pws = get_password_safe(&device)?;
let slots = pws