Skip to content

Commit 28976d7

Browse files
committed
api/show_mnemonic: add unit tests
This also allows us to keep track of the number of secure chip operations in all the scenarios.
1 parent 2b77bd6 commit 28976d7

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

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

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,149 @@ pub async fn process(hal: &mut impl crate::hal::Hal) -> Result<Response, Error>
6262
hal.ui().status("Backup created", true).await;
6363
Ok(Response::Success(pb::Success {}))
6464
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use super::*;
69+
70+
use alloc::boxed::Box;
71+
72+
use crate::hal::testing::TestingHal;
73+
use crate::workflow::testing::Screen;
74+
use bitbox02::testing::mock_memory;
75+
use util::bb02_async::block_on;
76+
77+
/// When not yet initialized, we show the mnemonic without a password check. This happens during
78+
/// wallet setup.
79+
#[test]
80+
fn test_process_uninitialized() {
81+
mock_memory();
82+
bitbox02::keystore::encrypt_and_store_seed(
83+
hex::decode("c7940c13479b8d9a6498f4e50d5a42e0d617bc8e8ac9f2b8cecf97e94c2b035c")
84+
.unwrap()
85+
.as_slice(),
86+
"password",
87+
)
88+
.unwrap();
89+
90+
assert!(!bitbox02::memory::is_initialized());
91+
92+
let mut mock_hal = TestingHal::new();
93+
mock_hal.ui.set_enter_string(Box::new(|_params| {
94+
panic!("unexpected call to enter password")
95+
}));
96+
97+
bitbox02::securechip::fake_event_counter_reset();
98+
assert_eq!(
99+
block_on(process(&mut mock_hal)),
100+
Ok(Response::Success(pb::Success {}))
101+
);
102+
// 1 operation for one copy_seed() to get the seed to display it.
103+
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
104+
105+
assert_eq!(
106+
mock_hal.ui.screens,
107+
vec![
108+
Screen::Confirm {
109+
title: "Warning".into(),
110+
body: "DO NOT share your\nrecovery words with\nanyone!".into(),
111+
longtouch: false
112+
},
113+
Screen::Confirm {
114+
title: "Recovery\nwords".into(),
115+
body: "Please write down\nthe following words".into(),
116+
longtouch: false
117+
},
118+
Screen::ShowAndConfirmMnemonic {
119+
mnemonic: "shy parrot age monkey rhythm snake mystery burden topic hello mouse script gesture tattoo demand float verify shoe recycle cool network better aspect list".into(),
120+
},
121+
Screen::Status {
122+
title: "Backup created".into(),
123+
success: true
124+
},
125+
]
126+
);
127+
}
128+
/// When initialized, a password check is prompted before displaying the mnemonic.
129+
#[test]
130+
fn test_process_initialized() {
131+
mock_memory();
132+
bitbox02::keystore::encrypt_and_store_seed(
133+
hex::decode("c7940c13479b8d9a6498f4e50d5a42e0d617bc8e8ac9f2b8cecf97e94c2b035c")
134+
.unwrap()
135+
.as_slice(),
136+
"password",
137+
)
138+
.unwrap();
139+
140+
bitbox02::memory::set_initialized().unwrap();
141+
142+
let mut mock_hal = TestingHal::new();
143+
mock_hal
144+
.ui
145+
.set_enter_string(Box::new(|_params| Ok("password".into())));
146+
147+
bitbox02::securechip::fake_event_counter_reset();
148+
assert_eq!(
149+
block_on(process(&mut mock_hal)),
150+
Ok(Response::Success(pb::Success {}))
151+
);
152+
assert_eq!(bitbox02::securechip::fake_event_counter(), 7);
153+
154+
assert_eq!(
155+
mock_hal.ui.screens,
156+
vec![
157+
Screen::Confirm {
158+
title: "Warning".into(),
159+
body: "DO NOT share your\nrecovery words with\nanyone!".into(),
160+
longtouch: false
161+
},
162+
Screen::Confirm {
163+
title: "Recovery\nwords".into(),
164+
body: "Please write down\nthe following words".into(),
165+
longtouch: false
166+
},
167+
Screen::ShowAndConfirmMnemonic {
168+
mnemonic: "shy parrot age monkey rhythm snake mystery burden topic hello mouse script gesture tattoo demand float verify shoe recycle cool network better aspect list".into(),
169+
},
170+
Screen::Status {
171+
title: "Backup created".into(),
172+
success: true
173+
},
174+
]
175+
);
176+
}
177+
178+
/// When initialized, a password check is prompted before displaying the mnemonic.
179+
/// This tests that we fail early if the wrong password is entered.
180+
#[test]
181+
fn test_process_initialized_wrong_password() {
182+
mock_memory();
183+
bitbox02::keystore::encrypt_and_store_seed(
184+
hex::decode("c7940c13479b8d9a6498f4e50d5a42e0d617bc8e8ac9f2b8cecf97e94c2b035c")
185+
.unwrap()
186+
.as_slice(),
187+
"password",
188+
)
189+
.unwrap();
190+
191+
bitbox02::memory::set_initialized().unwrap();
192+
193+
let mut mock_hal = TestingHal::new();
194+
mock_hal
195+
.ui
196+
.set_enter_string(Box::new(|_params| Ok("wrong password".into())));
197+
198+
bitbox02::securechip::fake_event_counter_reset();
199+
assert_eq!(block_on(process(&mut mock_hal)), Err(Error::Generic));
200+
assert_eq!(bitbox02::securechip::fake_event_counter(), 5);
201+
202+
assert_eq!(
203+
mock_hal.ui.screens,
204+
vec![Screen::Status {
205+
title: "Wrong password\n9 tries remain".into(),
206+
success: false,
207+
}]
208+
);
209+
}
210+
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub enum Screen {
4040
title: String,
4141
success: bool,
4242
},
43+
ShowAndConfirmMnemonic {
44+
mnemonic: String,
45+
},
4346
More,
4447
}
4548

@@ -169,6 +172,13 @@ impl Workflows for TestingWorkflows<'_> {
169172
) -> Result<u8, cancel::Error> {
170173
todo!("not used in unit tests yet");
171174
}
175+
176+
async fn show_and_confirm_mnemonic(&mut self, words: &[&str]) -> Result<(), cancel::Error> {
177+
self.screens.push(Screen::ShowAndConfirmMnemonic {
178+
mnemonic: words.join(" "),
179+
});
180+
Ok(())
181+
}
172182
}
173183

174184
impl<'a> TestingWorkflows<'a> {

0 commit comments

Comments
 (0)