diff options
Diffstat (limited to 'nitrocli/src')
-rw-r--r-- | nitrocli/src/args.rs | 15 | ||||
-rw-r--r-- | nitrocli/src/commands.rs | 44 | ||||
-rw-r--r-- | nitrocli/src/pinentry.rs | 10 |
3 files changed, 67 insertions, 2 deletions
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index edfd811..4341235 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -278,12 +278,14 @@ impl From<OtpMode> for nitrokey::OtpMode { #[derive(Debug)] enum PinCommand { Clear, + Unblock, } impl PinCommand { fn execute(&self, args: Vec<String>) -> Result<()> { match *self { PinCommand::Clear => pin_clear(args), + PinCommand::Unblock => pin_unblock(args), } } } @@ -295,6 +297,7 @@ impl fmt::Display for PinCommand { "{}", match *self { PinCommand::Clear => "clear", + PinCommand::Unblock => "unblock", } ) } @@ -306,6 +309,7 @@ impl str::FromStr for PinCommand { fn from_str(s: &str) -> result::Result<Self, Self::Err> { match s { "clear" => Ok(PinCommand::Clear), + "unblock" => Ok(PinCommand::Unblock), _ => Err(()), } } @@ -689,7 +693,7 @@ fn pin(args: Vec<String>) -> Result<()> { let _ = parser.refer(&mut subcommand).required().add_argument( "subcommand", argparse::Store, - "The subcommand to execute (clear)", + "The subcommand to execute (clear|unblock)", ); let _ = parser.refer(&mut subargs).add_argument( "arguments", @@ -713,6 +717,15 @@ fn pin_clear(args: Vec<String>) -> Result<()> { commands::pin_clear() } +/// Unblock and reset the user PIN. +fn pin_unblock(args: Vec<String>) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Unblocks and resets the user PIN"); + parse(&parser, args)?; + + commands::pin_unblock() +} + /// 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, Vec<String>)> { diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 7f25415..e3e2a14 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -474,6 +474,50 @@ pub fn pin_clear() -> Result<()> { Ok(()) } +fn check_pin(pintype: pinentry::PinType, pin: &str) -> Result<()> { + let minimum_length = match pintype { + pinentry::PinType::Admin => 8, + pinentry::PinType::User => 6, + }; + if pin.len() < minimum_length { + Err(Error::Error(format!( + "The PIN must be at least {} characters long", + minimum_length + ))) + } else { + Ok(()) + } +} + +fn choose_pin(pintype: pinentry::PinType) -> Result<String> { + pinentry::clear_passphrase(pintype)?; + let new_pin = pinentry::inquire_passphrase(pintype, pinentry::Mode::Choose, None)?; + pinentry::clear_passphrase(pintype)?; + let new_pin = String::from_utf8(new_pin)?; + check_pin(pintype, &new_pin)?; + + let confirm_pin = pinentry::inquire_passphrase(pintype, pinentry::Mode::Confirm, None)?; + pinentry::clear_passphrase(pintype)?; + let confirm_pin = String::from_utf8(confirm_pin)?; + + if new_pin != confirm_pin { + Err(Error::Error("Entered PINs do not match".to_string())) + } else { + Ok(new_pin) + } +} + +/// Unblock and reset the user PIN. +pub fn pin_unblock() -> Result<()> { + let device = get_device()?; + let user_pin = choose_pin(pinentry::PinType::User)?; + try_with_passphrase( + pinentry::PinType::Admin, + "Could not unblock the user PIN", + |admin_pin| device.unlock_user_pin(&admin_pin, &user_pin), + ) +} + #[cfg(test)] mod tests { use super::*; diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 90986be..33b5266 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -51,9 +51,13 @@ impl PinType { fn description(self, mode: Mode) -> &'static str { match self { PinType::Admin => match mode { + Mode::Choose => "Please enter a new admin PIN", + Mode::Confirm => "Please confirm the new admin PIN", Mode::Query => "Please enter the admin PIN", }, PinType::User => match mode { + Mode::Choose => "Please enter a new user PIN", + Mode::Confirm => "Please confirm the new user PIN", Mode::Query => "Please enter the user PIN", }, } @@ -67,13 +71,17 @@ impl PinType { /// quality bar is shown. #[derive(Clone, Copy, Debug, PartialEq)] pub enum Mode { + /// Let the user choose a new PIN. + Choose, + /// Let the user confirm the previously chosen PIN. + Confirm, /// Query an existing PIN. Query, } impl Mode { fn show_quality_bar(self) -> bool { - false + self == Mode::Choose } } |