Skip to content

Commit

Permalink
Merge remote-tracking branch 'benma/password-cancel'
Browse files Browse the repository at this point in the history
  • Loading branch information
benma committed Sep 29, 2022
2 parents d6fde8a + d9029ff commit 1c17397
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately.
- The BackupData.length field is now obsolete and always set to 0
- Port remaining protobuf code to Rust, remove the C nanopb protobuf dependency.
- Ethereum: replace ERC20 token names with their unit codes in the receive screen
- SetPassword now returns the UserAbort error instead of the Generic error if the user cancelled

### 9.12.0
- Ethereum: add support for EIP-712 structured data signing
Expand Down
15 changes: 15 additions & 0 deletions src/rust/bitbox02-rust/src/hww/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ impl core::convert::From<crate::workflow::cancel::Error> for Error {
}
}

impl core::convert::From<crate::workflow::password::EnterTwiceError> for Error {
fn from(error: crate::workflow::password::EnterTwiceError) -> Self {
match error {
crate::workflow::password::EnterTwiceError::DoNotMatch => {
// For backwards compatibility.
Error::Generic
}
crate::workflow::password::EnterTwiceError::Cancelled => {
// Added in v9.13.0.
Error::UserAbort
}
}
}
}

impl core::convert::From<crate::workflow::confirm::UserAbort> for Error {
fn from(_error: crate::workflow::confirm::UserAbort) -> Self {
Error::UserAbort
Expand Down
9 changes: 5 additions & 4 deletions src/rust/bitbox02-rust/src/hww/api/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,15 @@ pub async fn from_mnemonic(
// the process immediately. We break out only if the user confirms.
let password = loop {
match password::enter_twice().await {
Err(()) => {
let params = confirm::Params {
Err(password::EnterTwiceError::DoNotMatch) => {
confirm::confirm(&confirm::Params {
title: "",
body: "Passwords\ndo not match.\nTry again?",
..Default::default()
};
confirm::confirm(&params).await?;
})
.await?;
}
Err(password::EnterTwiceError::Cancelled) => return Err(Error::UserAbort),
Ok(password) => break password,
}
};
Expand Down
1 change: 0 additions & 1 deletion src/rust/bitbox02-rust/src/workflow/cancel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ pub async fn with_cancel<R>(
component: &mut bitbox02::ui::Component<'_>,
result_cell: &ResultCell<R>,
) -> Result<R, Error> {
*result_cell.borrow_mut() = None;
component.screen_stack_push();
loop {
let result = option(result_cell).await;
Expand Down
58 changes: 40 additions & 18 deletions src/rust/bitbox02-rust/src/workflow/password.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use super::{confirm, status, trinary_input_string};
use bitbox02::input::SafeInputString;

pub use trinary_input_string::CanCancel;
pub use trinary_input_string::{CanCancel, Error};

/// If `can_cancel` is `Yes`, the workflow can be cancelled.
/// If it is no, the result is always `Ok(())`.
Expand All @@ -29,7 +29,7 @@ pub async fn enter(
title: &str,
special_chars: bool,
can_cancel: CanCancel,
) -> Result<SafeInputString, super::cancel::Error> {
) -> Result<SafeInputString, Error> {
let params = trinary_input_string::Params {
title,
hide: true,
Expand All @@ -40,6 +40,19 @@ pub async fn enter(
trinary_input_string::enter(&params, can_cancel, "").await
}

pub enum EnterTwiceError {
DoNotMatch,
Cancelled,
}

impl core::convert::From<Error> for EnterTwiceError {
fn from(error: Error) -> Self {
match error {
Error::Cancelled => EnterTwiceError::Cancelled,
}
}
}

/// Prompt the user to enter a password twice. A warning is displayed
/// if the password has fewer than 4 chars. Returns `Err` if the two
/// passwords do not match, or if the user aborts at the warning.
Expand All @@ -48,26 +61,35 @@ pub async fn enter(
/// ```no_run
/// let pw = enter_twice().await.unwrap();
/// // use pw.
pub async fn enter_twice() -> Result<SafeInputString, ()> {
let password = enter("Set password", false, CanCancel::No)
.await
.expect("not cancelable");
let password_repeat = enter("Repeat password", false, CanCancel::No)
.await
.expect("not cancelable");
pub async fn enter_twice() -> Result<SafeInputString, EnterTwiceError> {
let password = enter("Set password", false, CanCancel::Yes).await?;
let password_repeat = enter("Repeat password", false, CanCancel::Yes).await?;
if password.as_str() != password_repeat.as_str() {
status::status("Passwords\ndo not match", false).await;
return Err(());
return Err(EnterTwiceError::DoNotMatch);
}
if password.as_str().len() < 4 {
let params = confirm::Params {
title: "WARNING",
body: "Your password\n has fewer than\n 4 characters.\nContinue?",
longtouch: true,
..Default::default()
};

confirm::confirm(&params).await.or(Err(()))?;
loop {
match confirm::confirm(&confirm::Params {
title: "WARNING",
body: "Your password\n has fewer than\n 4 characters.\nContinue?",
longtouch: true,
..Default::default()
})
.await
{
Ok(()) => break,
Err(confirm::UserAbort) => match confirm::confirm(&confirm::Params {
body: "Do you really\nwant to cancel?",
..Default::default()
})
.await
{
Ok(()) => return Err(EnterTwiceError::Cancelled),
Err(confirm::UserAbort) => {}
},
}
}
}
status::status("Success", true).await;
Ok(password)
Expand Down
14 changes: 5 additions & 9 deletions src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

pub use super::cancel::Error;
pub use super::cancel::{cancel, set_result, with_cancel, Error};
pub use bitbox02::ui::TrinaryInputStringParams as Params;

use crate::bb02_async::option;
use bitbox02::input::SafeInputString;
use core::cell::RefCell;

Expand All @@ -35,20 +34,17 @@ pub async fn enter(
can_cancel: CanCancel,
preset: &str,
) -> Result<SafeInputString, Error> {
let result = RefCell::new(None as Option<Result<SafeInputString, ()>>); // Err means cancelled.
let result = RefCell::new(None);
let mut component = bitbox02::ui::trinary_input_string_create(
params,
|string| *result.borrow_mut() = Some(Ok(string)),
|string| set_result(&result, string),
match can_cancel {
CanCancel::Yes => Some(Box::new(|| *result.borrow_mut() = Some(Err(())))),
CanCancel::Yes => Some(Box::new(|| cancel(&result))),
CanCancel::No => None,
},
);
if !preset.is_empty() {
bitbox02::ui::trinary_input_string_set_input(&mut component, preset);
}
component.screen_stack_push();
option(&result)
.await
.or(Err(super::cancel::Error::Cancelled))
with_cancel("", &mut component, &result).await
}

0 comments on commit 1c17397

Please sign in to comment.