bitbox02_rust: drop workflow::cancel::Error for hal::ui::UserAbort
What changed, and why it matters
This commit is a routine internal code cleanup. It removes a small, dedicated 'cancel' error type and replaces it with an existing, equivalent 'UserAbort' type in the hardware abstraction layer (HAL). The goal stated by the developer is to make the HAL self-contained so it can later be moved to its own crate. There is no change to user-visible behavior, no bug fix, and no security-related change.
No action required. This is a non-security refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch deletes src/rust/bitbox02-rust/src/workflow/cancel.rs and removes the workflow::cancel::Error enum. All call sites that previously returned or matched cancel::Error::Cancelled now use crate::hal::ui::UserAbort. The Ui trait and its BitBox02Ui and TestingUi implementations are updated to return UserAbort for cancellable UI workflows such as menu, show_mnemonic, quiz_mnemonic_word, trinary_input_string, and mnemonic entry. The From<crate::workflow::cancel::Error> conversion to hww::api::Error is removed because it is no longer needed. This is a pure refactoring with no functional or security change.
Changed components
bitbox02-firmware Rust HAL UI trait and implementationsworkflow/mnemonicworkflow/passwordworkflow/trinary_input_stringhww/api/errorInspect captured patch +49 / −72
diff --git a/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs b/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
index 23364df..fad06ac 100644
--- a/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
@@ -4,7 +4,7 @@ use alloc::string::String;
use crate::hal::Ui;
use crate::hal::ui::UserAbort;
-use crate::workflow::{cancel, confirm, sdcard, trinary_input_string};
+use crate::workflow::{confirm, sdcard, trinary_input_string};
pub struct BitBox02Ui;
@@ -49,14 +49,14 @@ impl Ui for BitBox02Ui {
params: &trinary_input_string::Params<'_>,
can_cancel: trinary_input_string::CanCancel,
preset: &str,
- ) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error> {
+ ) -> Result<zeroize::Zeroizing<String>, UserAbort> {
let can_cancel = match can_cancel {
trinary_input_string::CanCancel::Yes => true,
trinary_input_string::CanCancel::No => false,
};
bitbox02::ui::trinary_input_string(params, can_cancel, preset)
.await
- .or(Err(trinary_input_string::Error::Cancelled))
+ .map_err(|_| UserAbort)
}
#[inline(always)]
@@ -68,7 +68,7 @@ impl Ui for BitBox02Ui {
}
#[inline(always)]
- async fn menu(&mut self, words: &[&str], title: Option<&str>) -> Result<u8, cancel::Error> {
+ async fn menu(&mut self, words: &[&str], title: Option<&str>) -> Result<u8, UserAbort> {
match bitbox02::ui::menu(bitbox02::ui::MenuParams {
words,
title,
@@ -80,7 +80,7 @@ impl Ui for BitBox02Ui {
{
bitbox02::ui::MenuResponse::SelectWord(choice_idx) => Ok(choice_idx),
bitbox02::ui::MenuResponse::ContinueOnLast => panic!("unexpected continue-on-last"),
- bitbox02::ui::MenuResponse::Cancel => Err(cancel::Error::Cancelled),
+ bitbox02::ui::MenuResponse::Cancel => Err(UserAbort),
}
}
@@ -95,7 +95,7 @@ impl Ui for BitBox02Ui {
bitbox02::ui::trinary_choice(message, label_left, label_middle, label_right).await
}
- async fn show_mnemonic(&mut self, words: &[&str]) -> Result<(), cancel::Error> {
+ async fn show_mnemonic(&mut self, words: &[&str]) -> Result<(), UserAbort> {
match bitbox02::ui::menu(bitbox02::ui::MenuParams {
words,
title: None,
@@ -107,15 +107,11 @@ impl Ui for BitBox02Ui {
{
bitbox02::ui::MenuResponse::ContinueOnLast => Ok(()),
bitbox02::ui::MenuResponse::SelectWord(_) => panic!("unexpected select-word"),
- bitbox02::ui::MenuResponse::Cancel => Err(cancel::Error::Cancelled),
+ bitbox02::ui::MenuResponse::Cancel => Err(UserAbort),
}
}
- async fn quiz_mnemonic_word(
- &mut self,
- choices: &[&str],
- title: &str,
- ) -> Result<u8, cancel::Error> {
+ async fn quiz_mnemonic_word(&mut self, choices: &[&str], title: &str) -> Result<u8, UserAbort> {
match bitbox02::ui::menu(bitbox02::ui::MenuParams {
words: choices,
title: Some(title),
@@ -127,7 +123,7 @@ impl Ui for BitBox02Ui {
{
bitbox02::ui::MenuResponse::SelectWord(choice_idx) => Ok(choice_idx),
bitbox02::ui::MenuResponse::ContinueOnLast => panic!("unexpected continue-on-last"),
- bitbox02::ui::MenuResponse::Cancel => Err(cancel::Error::Cancelled),
+ bitbox02::ui::MenuResponse::Cancel => Err(UserAbort),
}
}
}
diff --git a/src/rust/bitbox02-rust/src/hal/testing/ui.rs b/src/rust/bitbox02-rust/src/hal/testing/ui.rs
index f1f079d..37870ac 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/ui.rs
@@ -2,7 +2,7 @@
use crate::hal::Ui;
use crate::hal::ui::UserAbort;
-use crate::workflow::{cancel, confirm, sdcard, trinary_input_string};
+use crate::workflow::{confirm, sdcard, trinary_input_string};
use alloc::boxed::Box;
use alloc::string::String;
@@ -119,7 +119,7 @@ impl Ui for TestingUi<'_> {
params: &trinary_input_string::Params<'_>,
_can_cancel: trinary_input_string::CanCancel,
_preset: &str,
- ) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error> {
+ ) -> Result<zeroize::Zeroizing<String>, UserAbort> {
self._enter_string.as_mut().unwrap()(params).map(zeroize::Zeroizing::new)
}
@@ -127,7 +127,7 @@ impl Ui for TestingUi<'_> {
Ok(())
}
- async fn menu(&mut self, _words: &[&str], _title: Option<&str>) -> Result<u8, cancel::Error> {
+ async fn menu(&mut self, _words: &[&str], _title: Option<&str>) -> Result<u8, UserAbort> {
todo!("not used in unit tests yet");
}
@@ -141,7 +141,7 @@ impl Ui for TestingUi<'_> {
todo!("not used in unit tests yet");
}
- async fn show_mnemonic(&mut self, _words: &[&str]) -> Result<(), cancel::Error> {
+ async fn show_mnemonic(&mut self, _words: &[&str]) -> Result<(), UserAbort> {
todo!("not used in unit tests yet");
}
@@ -149,7 +149,7 @@ impl Ui for TestingUi<'_> {
&mut self,
_choices: &[&str],
_title: &str,
- ) -> Result<u8, cancel::Error> {
+ ) -> Result<u8, UserAbort> {
todo!("not used in unit tests yet");
}
@@ -157,14 +157,14 @@ impl Ui for TestingUi<'_> {
&mut self,
_random: &mut impl crate::hal::Random,
words: &[&str],
- ) -> Result<(), cancel::Error> {
+ ) -> Result<(), UserAbort> {
self.screens.push(Screen::ShowAndConfirmMnemonic {
mnemonic: words.join(" "),
});
Ok(())
}
- async fn get_mnemonic(&mut self) -> Result<zeroize::Zeroizing<String>, cancel::Error>
+ async fn get_mnemonic(&mut self) -> Result<zeroize::Zeroizing<String>, UserAbort>
where
Self: Sized,
{
diff --git a/src/rust/bitbox02-rust/src/hal/ui.rs b/src/rust/bitbox02-rust/src/hal/ui.rs
index 31f8c0d..5ce01f3 100644
--- a/src/rust/bitbox02-rust/src/hal/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/ui.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
-use crate::workflow::{cancel, confirm, mnemonic, sdcard, trinary_input_string};
+use crate::workflow::{confirm, mnemonic, sdcard, trinary_input_string};
use alloc::string::String;
@@ -30,12 +30,12 @@ pub trait Ui {
params: &trinary_input_string::Params<'_>,
can_cancel: trinary_input_string::CanCancel,
preset: &str,
- ) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error>;
+ ) -> Result<zeroize::Zeroizing<String>, UserAbort>;
async fn insert_sdcard(&mut self) -> Result<(), sdcard::UserAbort>;
/// Returns the index of the word chosen by the user.
- async fn menu(&mut self, words: &[&str], title: Option<&str>) -> Result<u8, cancel::Error>;
+ async fn menu(&mut self, words: &[&str], title: Option<&str>) -> Result<u8, UserAbort>;
async fn trinary_choice(
&mut self,
@@ -46,15 +46,11 @@ pub trait Ui {
) -> bitbox02::ui::TrinaryChoice;
/// Display the BIP39 mnemonic to the user.
- async fn show_mnemonic(&mut self, words: &[&str]) -> Result<(), cancel::Error>;
+ async fn show_mnemonic(&mut self, words: &[&str]) -> Result<(), UserAbort>;
/// Display these BIP39 mnemonic word choices to the user as part of the quiz to confirm the
/// user backuped up the mnemonic correctly.
- async fn quiz_mnemonic_word(
- &mut self,
- choices: &[&str],
- title: &str,
- ) -> Result<u8, cancel::Error>;
+ async fn quiz_mnemonic_word(&mut self, choices: &[&str], title: &str) -> Result<u8, UserAbort>;
/// Display the mnemonic words and have the user confirm them in a multiple-choice quiz.
///
@@ -67,7 +63,7 @@ pub trait Ui {
&mut self,
random: &mut impl crate::hal::Random,
words: &[&str],
- ) -> Result<(), cancel::Error>
+ ) -> Result<(), UserAbort>
where
Self: Sized,
{
@@ -78,7 +74,7 @@ pub trait Ui {
///
/// This function is defined in the HAL so unit tests can easily mock it. Real implementations
/// should leave the default implementation.
- async fn get_mnemonic(&mut self) -> Result<zeroize::Zeroizing<String>, cancel::Error>
+ async fn get_mnemonic(&mut self) -> Result<zeroize::Zeroizing<String>, UserAbort>
where
Self: Sized,
{
diff --git a/src/rust/bitbox02-rust/src/hww/api/error.rs b/src/rust/bitbox02-rust/src/hww/api/error.rs
index 5deaa3a..ac456c6 100644
--- a/src/rust/bitbox02-rust/src/hww/api/error.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/error.rs
@@ -35,12 +35,6 @@ impl core::convert::From<crate::hal::memory::Error> for Error {
}
}
-impl core::convert::From<crate::workflow::cancel::Error> for Error {
- fn from(_error: crate::workflow::cancel::Error) -> Self {
- Error::UserAbort
- }
-}
-
impl core::convert::From<crate::workflow::password::EnterError> for Error {
fn from(error: crate::workflow::password::EnterError) -> Self {
match error {
diff --git a/src/rust/bitbox02-rust/src/workflow.rs b/src/rust/bitbox02-rust/src/workflow.rs
index 78e5551..3939396 100644
--- a/src/rust/bitbox02-rust/src/workflow.rs
+++ b/src/rust/bitbox02-rust/src/workflow.rs
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
-pub mod cancel;
pub mod confirm;
#[cfg_attr(
all(feature = "c-unit-testing", not(feature = "testing")),
diff --git a/src/rust/bitbox02-rust/src/workflow/cancel.rs b/src/rust/bitbox02-rust/src/workflow/cancel.rs
deleted file mode 100644
index 77cbe6e..0000000
--- a/src/rust/bitbox02-rust/src/workflow/cancel.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#[derive(Debug)]
-pub enum Error {
- Cancelled,
-}
diff --git a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
index be3abbc..b45e0a3 100644
--- a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
+++ b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
-pub use super::cancel::Error as CancelError;
use super::confirm;
use super::trinary_input_string;
+use crate::hal::ui::UserAbort;
use alloc::string::String;
use alloc::vec::Vec;
@@ -67,7 +67,7 @@ pub async fn show_and_confirm_mnemonic(
hal_ui: &mut impl crate::hal::Ui,
hal_random: &mut impl crate::hal::Random,
words: &[&str],
-) -> Result<(), CancelError> {
+) -> Result<(), UserAbort> {
hal_ui
.confirm(&confirm::Params {
title: "",
@@ -76,7 +76,7 @@ pub async fn show_and_confirm_mnemonic(
..Default::default()
})
.await
- .map_err(|_| CancelError::Cancelled)?;
+ .map_err(|_| UserAbort)?;
// Part 1) Scroll through words
hal_ui.show_mnemonic(words).await?;
@@ -178,12 +178,12 @@ fn lastword_choices_strings(entered_words: &[&str]) -> Vec<zeroize::Zeroizing<St
/// Select the 24th word from a list of 8 valid candidate words presented as a menu.
/// Returns `Ok(None)` if the user chooses "None of them".
/// Returns `Ok(Some(word))` if the user chooses a word.
-/// Returns `Err(CancelError::Cancelled)` if the user cancels.
+/// Returns `Err(UserAbort)` if the user cancels.
async fn get_24th_word(
hal_ui: &mut impl crate::hal::Ui,
title: &str,
entered_words: &[&str],
-) -> Result<Option<zeroize::Zeroizing<String>>, CancelError> {
+) -> Result<Option<zeroize::Zeroizing<String>>, UserAbort> {
let mut choices = lastword_choices_strings(entered_words);
// Add one more menu entry.
let none_of_them_idx = {
@@ -192,7 +192,7 @@ async fn get_24th_word(
};
loop {
match hal_ui.menu(&as_str_vec(&choices), Some(title)).await {
- Err(CancelError::Cancelled) => return Err(CancelError::Cancelled),
+ Err(UserAbort) => return Err(UserAbort),
Ok(choice_idx) if choice_idx as usize == none_of_them_idx => {
let params = confirm::Params {
title: "",
@@ -226,12 +226,12 @@ async fn get_24th_word(
/// is the trinary input keyboard with the wordlist restricted to these candidates.
///
/// Returns `Ok(word)` if the user chooses a word.
-/// Returns `Err(CancelError::Cancelled)` if the user cancels.
+/// Returns `Err(UserAbort)` if the user cancels.
async fn get_12th_18th_word(
hal_ui: &mut impl crate::hal::Ui,
title: &str,
entered_words: &[&str],
-) -> Result<zeroize::Zeroizing<String>, CancelError> {
+) -> Result<zeroize::Zeroizing<String>, UserAbort> {
// With 12/18 words there are 128/32 candidates, so we limit the keyboard to allow entering only
// these.
loop {
@@ -266,7 +266,7 @@ async fn get_12th_18th_word(
/// Retrieve a BIP39 mnemonic sentence of 12 or 24 words from the user.
pub async fn get(
hal_ui: &mut impl crate::hal::Ui,
-) -> Result<zeroize::Zeroizing<String>, CancelError> {
+) -> Result<zeroize::Zeroizing<String>, UserAbort> {
let num_words: usize = match hal_ui
.trinary_choice("How many words?", Some("12"), None, Some("24"))
.await
@@ -293,8 +293,7 @@ pub async fn get(
// goes forward again.
let preset = entered_words[word_idx].as_str();
- let user_entry: Result<zeroize::Zeroizing<String>, CancelError> = if word_idx
- == num_words - 1
+ let user_entry: Result<zeroize::Zeroizing<String>, UserAbort> = if word_idx == num_words - 1
{
// For the last word, we can restrict to a subset of bip39 words that fulfil the
// checksum requirement. This special case exists so that users can generate a seed
@@ -303,7 +302,7 @@ pub async fn get(
if num_words == 24 {
// With 24 words there are only 8 valid candidates. We presnet them as a menu.
match get_24th_word(hal_ui, &title, &as_str_vec(&entered_words[..word_idx])).await {
- Ok(None) => return Err(CancelError::Cancelled),
+ Ok(None) => return Err(UserAbort),
Ok(Some(r)) => Ok(r),
Err(e) => Err(e),
}
@@ -325,7 +324,7 @@ pub async fn get(
};
match user_entry {
- Err(CancelError::Cancelled) => {
+ Err(UserAbort) => {
// User clicked the cancel button. There are two choices:
enum GetWordError {
Cancel,
@@ -343,7 +342,7 @@ pub async fn get(
.menu(&["Edit previous word", "Cancel restore"], Some("Choose"))
.await
{
- Err(CancelError::Cancelled) => {
+ Err(UserAbort) => {
// Cancel cancelled.
continue;
}
@@ -362,11 +361,11 @@ pub async fn get(
..Default::default()
};
- if let Err(crate::hal::ui::UserAbort) = hal_ui.confirm(¶ms).await {
+ if let Err(UserAbort) = hal_ui.confirm(¶ms).await {
// Cancel cancelled.
continue;
}
- return Err(CancelError::Cancelled);
+ return Err(UserAbort);
}
}
}
diff --git a/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs b/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs
index 2a19297..f209675 100644
--- a/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs
+++ b/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
-pub use super::cancel::Error as CancelError;
+use crate::hal::ui::UserAbort;
use alloc::string::String;
use alloc::string::ToString;
@@ -9,7 +9,7 @@ pub async fn show_and_confirm_mnemonic(
_ui: &mut impl crate::hal::Ui,
_random: &mut impl crate::hal::Random,
words: &[&str],
-) -> Result<(), CancelError> {
+) -> Result<(), UserAbort> {
for word in words.iter() {
bitbox02::println_stdout(word);
}
@@ -18,7 +18,7 @@ pub async fn show_and_confirm_mnemonic(
Ok(())
}
-pub async fn get(_ui: &mut impl crate::hal::Ui) -> Result<zeroize::Zeroizing<String>, CancelError> {
+pub async fn get(_ui: &mut impl crate::hal::Ui) -> Result<zeroize::Zeroizing<String>, UserAbort> {
let words = "boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide";
bitbox02::println_stdout("Restored from recovery words below:");
bitbox02::println_stdout(words);
diff --git a/src/rust/bitbox02-rust/src/workflow/password.rs b/src/rust/bitbox02-rust/src/workflow/password.rs
index f18de04..b20b670 100644
--- a/src/rust/bitbox02-rust/src/workflow/password.rs
+++ b/src/rust/bitbox02-rust/src/workflow/password.rs
@@ -2,10 +2,11 @@
use super::{confirm, trinary_input_string};
use crate::hal::Ui;
+use crate::hal::ui::UserAbort;
use crate::hal::{Memory, memory::SecurechipType};
-pub use trinary_input_string::{CanCancel, Error};
+pub use trinary_input_string::CanCancel;
use alloc::string::String;
@@ -72,9 +73,9 @@ pub async fn enter(
loop {
match hal.ui().enter_string(¶ms, can_cancel, "").await {
Ok(pw) => return Ok(pw),
- Err(Error::Cancelled) => match prompt_cancel(hal).await {
+ Err(UserAbort) => match prompt_cancel(hal).await {
Ok(()) => return Err(EnterError::Cancelled),
- Err(crate::hal::ui::UserAbort) => {}
+ Err(UserAbort) => {}
},
}
}
@@ -133,9 +134,9 @@ pub async fn enter_twice(
.await
{
Ok(()) => break,
- Err(crate::hal::ui::UserAbort) => match prompt_cancel(hal).await {
+ Err(UserAbort) => match prompt_cancel(hal).await {
Ok(()) => return Err(EnterTwiceError::EnterError(EnterError::Cancelled)),
- Err(crate::hal::ui::UserAbort) => {}
+ Err(UserAbort) => {}
},
}
}
@@ -195,9 +196,7 @@ mod tests {
fn test_enter_cancelled() {
let mut hal = TestingHal::new();
hal.memory.set_securechip_type(SecurechipType::Atecc);
- hal.ui.set_enter_string(Box::new(|_params| {
- Err(trinary_input_string::Error::Cancelled)
- }));
+ hal.ui.set_enter_string(Box::new(|_params| Err(UserAbort)));
let result = block_on(enter(
&mut hal,
diff --git a/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs b/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
index 3643d18..c8e2edd 100644
--- a/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
+++ b/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
-pub use super::cancel::Error;
+pub use crate::hal::ui::UserAbort as Error;
pub use bitbox02::ui::{TrinaryInputStringParams as Params, trinary_input_string};
#[derive(Copy, Clone)]
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.