Skip to content

Commit 69aa454

Browse files
committed
api: add trinary_input_string to the Workflows trait
1 parent 6fc2f2e commit 69aa454

File tree

7 files changed

+127
-81
lines changed

7 files changed

+127
-81
lines changed

src/rust/bitbox02-rust/src/hww/api/bip85.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,18 @@ async fn process_bip39<W: Workflows>(workflows: &mut W) -> Result<(), Error> {
8383
match menu::pick(&["0", "1", "2", "3", "4", "More"], Some("Select index")).await? {
8484
i @ 0..=4 => i.into(),
8585
5 => {
86-
let number_string = trinary_input_string::enter(
87-
&trinary_input_string::Params {
88-
title: "Enter index",
89-
number_input: true,
90-
longtouch: true,
91-
..Default::default()
92-
},
93-
trinary_input_string::CanCancel::Yes,
94-
"",
95-
)
96-
.await?;
86+
let number_string = workflows
87+
.enter_string(
88+
&trinary_input_string::Params {
89+
title: "Enter index",
90+
number_input: true,
91+
longtouch: true,
92+
..Default::default()
93+
},
94+
trinary_input_string::CanCancel::Yes,
95+
"",
96+
)
97+
.await?;
9798
match number_string.as_str().parse::<u32>() {
9899
Ok(i) if i < util::bip32::HARDENED => i,
99100
_ => {

src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,17 @@ async fn get_name<W: Workflows>(
8080
})
8181
.await?;
8282

83-
let name = trinary_input_string::enter(
84-
&trinary_input_string::Params {
85-
title: "Enter account name",
86-
longtouch: true,
87-
..Default::default()
88-
},
89-
trinary_input_string::CanCancel::Yes,
90-
"",
91-
)
92-
.await?;
83+
let name = workflows
84+
.enter_string(
85+
&trinary_input_string::Params {
86+
title: "Enter account name",
87+
longtouch: true,
88+
..Default::default()
89+
},
90+
trinary_input_string::CanCancel::Yes,
91+
"",
92+
)
93+
.await?;
9394
// We truncate the user input string to fit into the maximum allowed multisig
9495
// account name length. This is not very nice, but it has to do until we have some
9596
// sort of indication in the input component.

src/rust/bitbox02-rust/src/hww/api/set_password.rs

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,28 +50,37 @@ mod tests {
5050
use super::*;
5151

5252
use crate::bb02_async::block_on;
53-
use crate::workflow::RealWorkflows;
53+
use crate::workflow::testing::TestingWorkflows;
5454
use bitbox02::testing::{mock, mock_memory, Data};
5555

5656
use alloc::boxed::Box;
5757

5858
#[test]
5959
fn test_process() {
6060
mock_memory();
61-
mock(Data {
62-
ui_trinary_input_string_create: Some(Box::new(|_params| "password".into())),
63-
..Default::default()
64-
});
65-
assert!(keystore::is_locked());
61+
keystore::lock();
62+
let mut counter = 0u32;
63+
let mut mock_workflows = TestingWorkflows::new();
64+
mock_workflows.set_enter_string(Box::new(|params| {
65+
counter += 1;
66+
match counter {
67+
1 => assert_eq!(params.title, "Set password"),
68+
2 => assert_eq!(params.title, "Repeat password"),
69+
_ => panic!("too many user inputs"),
70+
}
71+
Ok("password".into())
72+
}));
6673
assert_eq!(
6774
block_on(process(
68-
&mut RealWorkflows,
75+
&mut mock_workflows,
6976
&pb::SetPasswordRequest {
7077
entropy: b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_vec(),
7178
}
7279
)),
7380
Ok(Response::Success(pb::Success {}))
7481
);
82+
drop(mock_workflows); // to remove mutable borrow of counter
83+
assert_eq!(counter, 2);
7584
assert!(!keystore::is_locked());
7685
assert!(keystore::copy_seed().unwrap().len() == 32);
7786
}
@@ -80,14 +89,12 @@ mod tests {
8089
#[test]
8190
fn test_process_16_bytes() {
8291
mock_memory();
83-
mock(Data {
84-
ui_trinary_input_string_create: Some(Box::new(|_params| "password".into())),
85-
..Default::default()
86-
});
87-
assert!(keystore::is_locked());
92+
keystore::lock();
93+
let mut mock_workflows = TestingWorkflows::new();
94+
mock_workflows.set_enter_string(Box::new(|_params| Ok("password".into())));
8895
assert_eq!(
8996
block_on(process(
90-
&mut RealWorkflows,
97+
&mut mock_workflows,
9198
&pb::SetPasswordRequest {
9299
entropy: b"aaaaaaaaaaaaaaaa".to_vec(),
93100
}
@@ -102,14 +109,13 @@ mod tests {
102109
#[test]
103110
fn test_process_invalid_host_entropy() {
104111
mock_memory();
105-
mock(Data {
106-
ui_trinary_input_string_create: Some(Box::new(|_params| "password".into())),
107-
..Default::default()
108-
});
112+
keystore::lock();
113+
let mut mock_workflows = TestingWorkflows::new();
114+
mock_workflows.set_enter_string(Box::new(|_params| Ok("password".into())));
109115
assert!(keystore::is_locked());
110116
assert_eq!(
111117
block_on(process(
112-
&mut RealWorkflows,
118+
&mut mock_workflows,
113119
&pb::SetPasswordRequest {
114120
entropy: b"aaaaaaaaaaaaaaaaa".to_vec(),
115121
}
@@ -122,24 +128,20 @@ mod tests {
122128
#[test]
123129
fn test_process_2nd_password_doesnt_match() {
124130
mock_memory();
125-
static mut COUNTER: u32 = 0;
126-
mock(Data {
127-
ui_trinary_input_string_create: Some(Box::new(|_params| {
128-
match unsafe {
129-
COUNTER += 1;
130-
COUNTER
131-
} {
132-
1 => "password".into(),
133-
2 => "wrong".into(),
134-
_ => panic!("too many user inputs"),
135-
}
136-
})),
137-
..Default::default()
138-
});
139-
assert!(keystore::is_locked());
131+
keystore::lock();
132+
let mut counter = 0u32;
133+
let mut mock_workflows = TestingWorkflows::new();
134+
mock_workflows.set_enter_string(Box::new(|_params| {
135+
counter += 1;
136+
Ok(match counter {
137+
1 => "password".into(),
138+
2 => "wrong".into(),
139+
_ => panic!("too many user inputs"),
140+
})
141+
}));
140142
assert_eq!(
141143
block_on(process(
142-
&mut RealWorkflows,
144+
&mut mock_workflows,
143145
&pb::SetPasswordRequest {
144146
entropy: b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_vec(),
145147
}

src/rust/bitbox02-rust/src/workflow.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub mod trinary_input_string;
2929
pub mod unlock;
3030
pub mod verify_message;
3131

32+
use alloc::string::String;
33+
3234
#[allow(async_fn_in_trait)]
3335
pub trait Workflows {
3436
async fn confirm(&mut self, params: &confirm::Params<'_>) -> Result<(), confirm::UserAbort>;
@@ -47,6 +49,13 @@ pub trait Workflows {
4749
) -> Result<(), transaction::UserAbort>;
4850

4951
async fn status(&mut self, title: &str, status_success: bool);
52+
53+
async fn enter_string(
54+
&mut self,
55+
params: &trinary_input_string::Params<'_>,
56+
can_cancel: trinary_input_string::CanCancel,
57+
preset: &str,
58+
) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error>;
5059
}
5160

5261
pub struct RealWorkflows;
@@ -80,4 +89,14 @@ impl Workflows for RealWorkflows {
8089
async fn status(&mut self, title: &str, status_success: bool) {
8190
status::status(title, status_success).await
8291
}
92+
93+
#[inline(always)]
94+
async fn enter_string(
95+
&mut self,
96+
params: &trinary_input_string::Params<'_>,
97+
can_cancel: trinary_input_string::CanCancel,
98+
preset: &str,
99+
) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error> {
100+
trinary_input_string::enter(params, can_cancel, preset).await
101+
}
83102
}

src/rust/bitbox02-rust/src/workflow/mnemonic.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,17 @@ async fn get_12th_18th_word<W: Workflows>(
270270
loop {
271271
let choices = lastword_choices(entered_words);
272272
let candidates = bitbox02::keystore::get_bip39_wordlist(Some(&choices));
273-
let word = trinary_input_string::enter(
274-
&trinary_input_string::Params {
275-
title,
276-
wordlist: Some(&candidates),
277-
..Default::default()
278-
},
279-
trinary_input_string::CanCancel::Yes,
280-
"",
281-
)
282-
.await?;
273+
let word = workflows
274+
.enter_string(
275+
&trinary_input_string::Params {
276+
title,
277+
wordlist: Some(&candidates),
278+
..Default::default()
279+
},
280+
trinary_input_string::CanCancel::Yes,
281+
"",
282+
)
283+
.await?;
283284

284285
// Confirm word picked again, as a typo here would be extremely annoying. Double checking
285286
// is also safer, as the user might not even realize they made a typo.
@@ -348,17 +349,18 @@ pub async fn get<W: Workflows>(
348349
get_12th_18th_word(workflows, &title, &as_str_vec(&entered_words[..word_idx])).await
349350
}
350351
} else {
351-
trinary_input_string::enter(
352-
&trinary_input_string::Params {
353-
title: &title,
354-
wordlist: Some(&bip39_wordlist),
355-
..Default::default()
356-
},
357-
trinary_input_string::CanCancel::Yes,
358-
preset,
359-
)
360-
.await
361-
.into()
352+
workflows
353+
.enter_string(
354+
&trinary_input_string::Params {
355+
title: &title,
356+
wordlist: Some(&bip39_wordlist),
357+
..Default::default()
358+
},
359+
trinary_input_string::CanCancel::Yes,
360+
preset,
361+
)
362+
.await
363+
.into()
362364
};
363365

364366
match user_entry {

src/rust/bitbox02-rust/src/workflow/password.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub async fn enter<W: Workflows>(
5050
};
5151

5252
loop {
53-
match trinary_input_string::enter(&params, can_cancel, "").await {
53+
match workflows.enter_string(&params, can_cancel, "").await {
5454
o @ Ok(_) => return o,
5555
Err(Error::Cancelled) => match prompt_cancel(workflows).await {
5656
Ok(()) => return Err(Error::Cancelled),

src/rust/bitbox02-rust/src/workflow/testing.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use super::{confirm, transaction, Workflows};
15+
use super::{confirm, transaction, trinary_input_string, Workflows};
1616

17+
use alloc::boxed::Box;
1718
use alloc::string::String;
1819
use alloc::vec::Vec;
1920

@@ -40,14 +41,20 @@ pub enum Screen {
4041
More,
4142
}
4243

44+
type EnterStringCb<'a> = Box<
45+
dyn FnMut(&trinary_input_string::Params<'_>) -> Result<String, trinary_input_string::Error>
46+
+ 'a,
47+
>;
48+
4349
/// An Workflows implementation for unit tests. Collects all screens and provides helper functions
4450
/// to verify them.
45-
pub struct TestingWorkflows {
51+
pub struct TestingWorkflows<'a> {
4652
_abort_nth: Option<usize>,
4753
pub screens: Vec<Screen>,
54+
_enter_string: Option<EnterStringCb<'a>>,
4855
}
4956

50-
impl Workflows for TestingWorkflows {
57+
impl Workflows for TestingWorkflows<'_> {
5158
async fn confirm(&mut self, params: &confirm::Params<'_>) -> Result<(), confirm::UserAbort> {
5259
self.screens.push(Screen::Confirm {
5360
title: params.title.into(),
@@ -117,13 +124,23 @@ impl Workflows for TestingWorkflows {
117124
panic!("canot abort status screen");
118125
}
119126
}
127+
128+
async fn enter_string(
129+
&mut self,
130+
params: &trinary_input_string::Params<'_>,
131+
_can_cancel: trinary_input_string::CanCancel,
132+
_preset: &str,
133+
) -> Result<zeroize::Zeroizing<String>, trinary_input_string::Error> {
134+
self._enter_string.as_mut().unwrap()(params).map(zeroize::Zeroizing::new)
135+
}
120136
}
121137

122-
impl TestingWorkflows {
138+
impl<'a> TestingWorkflows<'a> {
123139
pub fn new() -> Self {
124140
Self {
125141
screens: vec![],
126142
_abort_nth: None,
143+
_enter_string: None,
127144
}
128145
}
129146

@@ -139,4 +156,8 @@ impl TestingWorkflows {
139156
_ => false,
140157
})
141158
}
159+
160+
pub fn set_enter_string(&mut self, cb: EnterStringCb<'a>) {
161+
self._enter_string = Some(cb);
162+
}
142163
}

0 commit comments

Comments
 (0)