Skip to content

Commit 6fc2f2e

Browse files
committed
api: use Workflows trait in more calls
1 parent 6062eae commit 6fc2f2e

22 files changed

+716
-532
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ static mut CONFIRM_TITLE: Option<String> = None;
4040
static mut CONFIRM_BODY: Option<String> = None;
4141
static mut CONFIRM_PARAMS: Option<confirm::Params> = None;
4242
static mut CONFIRM_STATE: TaskState<'static, Result<(), confirm::UserAbort>> = TaskState::Nothing;
43+
static mut REAL_WORKFLOWS: bitbox02_rust::workflow::RealWorkflows =
44+
bitbox02_rust::workflow::RealWorkflows;
4345

4446
#[no_mangle]
4547
pub unsafe extern "C" fn rust_workflow_spawn_unlock() {
46-
UNLOCK_STATE = TaskState::Running(Box::pin(bitbox02_rust::workflow::unlock::unlock()));
48+
UNLOCK_STATE = TaskState::Running(Box::pin(bitbox02_rust::workflow::unlock::unlock(
49+
&mut REAL_WORKFLOWS,
50+
)));
4751
}
4852

4953
#[no_mangle]

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod noise;
1717

1818
use alloc::vec::Vec;
1919

20-
use crate::workflow::RealWorkflows;
20+
use crate::workflow::{RealWorkflows, Workflows};
2121

2222
const OP_UNLOCK: u8 = b'u';
2323
const OP_ATTESTATION: u8 = b'a';
@@ -75,8 +75,8 @@ pub async fn next_request(
7575
}
7676

7777
/// Process OP_UNLOCK.
78-
async fn api_unlock() -> Vec<u8> {
79-
match crate::workflow::unlock::unlock().await {
78+
async fn api_unlock<W: Workflows>(workflows: &mut W) -> Vec<u8> {
79+
match crate::workflow::unlock::unlock(workflows).await {
8080
Ok(()) => [OP_STATUS_SUCCESS].to_vec(),
8181
Err(()) => [OP_STATUS_FAILURE_UNINITIALIZED].to_vec(),
8282
}
@@ -118,7 +118,7 @@ pub async fn process_packet(usb_in: Vec<u8>) -> Vec<u8> {
118118
let workflows = &mut RealWorkflows;
119119

120120
match usb_in.split_first() {
121-
Some((&OP_UNLOCK, b"")) => return api_unlock().await,
121+
Some((&OP_UNLOCK, b"")) => return api_unlock(workflows).await,
122122
Some((&OP_ATTESTATION, rest)) => return api_attestation(rest),
123123
_ => (),
124124
}

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,26 @@ async fn process_api<W: Workflows>(
164164
request: &Request,
165165
) -> Result<Response, Error> {
166166
match request {
167-
Request::Reboot(ref request) => system::reboot(request).await,
167+
Request::Reboot(ref request) => system::reboot(workflows, request).await,
168168
Request::DeviceInfo(_) => device_info::process(),
169-
Request::DeviceName(ref request) => set_device_name::process(request).await,
170-
Request::SetPassword(ref request) => set_password::process(request).await,
171-
Request::Reset(_) => reset::process().await,
169+
Request::DeviceName(ref request) => set_device_name::process(workflows, request).await,
170+
Request::SetPassword(ref request) => set_password::process(workflows, request).await,
171+
Request::Reset(_) => reset::process(workflows).await,
172172
Request::SetMnemonicPassphraseEnabled(ref request) => {
173-
set_mnemonic_passphrase_enabled::process(request).await
173+
set_mnemonic_passphrase_enabled::process(workflows, request).await
174174
}
175175
Request::InsertRemoveSdcard(ref request) => sdcard::process(request).await,
176176
Request::ListBackups(_) => backup::list(),
177177
Request::CheckSdcard(_) => Ok(Response::CheckSdcard(pb::CheckSdCardResponse {
178178
inserted: bitbox02::sd::sdcard_inserted(),
179179
})),
180-
Request::CheckBackup(ref request) => backup::check(request).await,
181-
Request::CreateBackup(ref request) => backup::create(request).await,
182-
Request::RestoreBackup(ref request) => restore::from_file(request).await,
183-
Request::ShowMnemonic(_) => show_mnemonic::process().await,
184-
Request::RestoreFromMnemonic(ref request) => restore::from_mnemonic(request).await,
180+
Request::CheckBackup(ref request) => backup::check(workflows, request).await,
181+
Request::CreateBackup(ref request) => backup::create(workflows, request).await,
182+
Request::RestoreBackup(ref request) => restore::from_file(workflows, request).await,
183+
Request::ShowMnemonic(_) => show_mnemonic::process(workflows).await,
184+
Request::RestoreFromMnemonic(ref request) => {
185+
restore::from_mnemonic(workflows, request).await
186+
}
185187
Request::ElectrumEncryptionKey(ref request) => electrum::process(request).await,
186188

187189
#[cfg(feature = "app-ethereum")]
@@ -206,7 +208,7 @@ async fn process_api<W: Workflows>(
206208
.map(|r| Response::Cardano(pb::CardanoResponse { response: Some(r) })),
207209
#[cfg(not(feature = "app-cardano"))]
208210
Request::Cardano(_) => Err(Error::Disabled),
209-
Request::Bip85(ref request) => bip85::process(request).await,
211+
Request::Bip85(ref request) => bip85::process(workflows, request).await,
210212
_ => Err(Error::InvalidInput),
211213
}
212214
}

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

Lines changed: 102 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ use alloc::vec::Vec;
2020
use pb::response::Response;
2121

2222
use crate::backup;
23-
use crate::workflow::{confirm, status, unlock};
23+
use crate::workflow::{confirm, unlock, Workflows};
2424

25-
pub async fn check(
25+
pub async fn check<W: Workflows>(
26+
workflows: &mut W,
2627
&pb::CheckBackupRequest { silent }: &pb::CheckBackupRequest,
2728
) -> Result<Response, Error> {
2829
if !bitbox02::sd::sdcard_inserted() {
@@ -34,29 +35,31 @@ pub async fn check(
3435
let (backup_data, metadata) = backup::load(&id)?;
3536
if seed.as_slice() != backup_data.get_seed() {
3637
if !silent {
37-
status::status("Backup missing\nor invalid", false).await;
38+
workflows.status("Backup missing\nor invalid", false).await;
3839
}
3940
return Err(Error::Generic);
4041
}
4142
if !silent {
42-
confirm::confirm(&confirm::Params {
43-
title: "Name?",
44-
body: &metadata.name,
45-
scrollable: true,
46-
accept_is_nextarrow: true,
47-
..Default::default()
48-
})
49-
.await?;
43+
workflows
44+
.confirm(&confirm::Params {
45+
title: "Name?",
46+
body: &metadata.name,
47+
scrollable: true,
48+
accept_is_nextarrow: true,
49+
..Default::default()
50+
})
51+
.await?;
5052

51-
confirm::confirm(&confirm::Params {
52-
title: "ID?",
53-
body: &id,
54-
scrollable: true,
55-
..Default::default()
56-
})
57-
.await?;
53+
workflows
54+
.confirm(&confirm::Params {
55+
title: "ID?",
56+
body: &id,
57+
scrollable: true,
58+
..Default::default()
59+
})
60+
.await?;
5861

59-
status::status("Backup valid", true).await;
62+
workflows.status("Backup valid", true).await;
6063
}
6164
Ok(Response::CheckBackup(pb::CheckBackupResponse { id }))
6265
}
@@ -69,19 +72,21 @@ pub async fn check(
6972
/// If the device is initialized, an existing backup is overwritten, but the seed birthdate is
7073
/// retained from the previous backup. If no backup existed, the seed birthdate is set to 0, meaning
7174
/// it is unknown.
72-
pub async fn create(
75+
pub async fn create<W: Workflows>(
76+
workflows: &mut W,
7377
&pb::CreateBackupRequest {
7478
timestamp,
7579
timezone_offset,
7680
}: &pb::CreateBackupRequest,
7781
) -> Result<Response, Error> {
78-
confirm::confirm(&confirm::Params {
79-
title: "Is today?",
80-
body: &bitbox02::format_datetime(timestamp, timezone_offset, true)
81-
.map_err(|_| Error::InvalidInput)?,
82-
..Default::default()
83-
})
84-
.await?;
82+
workflows
83+
.confirm(&confirm::Params {
84+
title: "Is today?",
85+
body: &bitbox02::format_datetime(timestamp, timezone_offset, true)
86+
.map_err(|_| Error::InvalidInput)?,
87+
..Default::default()
88+
})
89+
.await?;
8590

8691
// Wait for sd card
8792
super::sdcard::process(&pb::InsertRemoveSdCardRequest {
@@ -92,7 +97,7 @@ pub async fn create(
9297
let is_initialized = bitbox02::memory::is_initialized();
9398

9499
if is_initialized {
95-
unlock::unlock_keystore("Unlock device", unlock::CanCancel::Yes).await?;
100+
unlock::unlock_keystore(workflows, "Unlock device", unlock::CanCancel::Yes).await?;
96101
}
97102

98103
let seed = bitbox02::keystore::copy_seed()?;
@@ -122,12 +127,12 @@ pub async fn create(
122127
// process again.
123128
let _ = bitbox02::memory::set_initialized();
124129

125-
status::status("Backup created", true).await;
130+
workflows.status("Backup created", true).await;
126131
Ok(Response::Success(pb::Success {}))
127132
}
128133
Err(err) => {
129134
let msg = format!("Backup not created\nPlease contact\nsupport ({:?})", err);
130-
status::status(&msg, false).await;
135+
workflows.status(&msg, false).await;
131136
Err(Error::Generic)
132137
}
133138
}
@@ -154,6 +159,7 @@ mod tests {
154159
use super::*;
155160

156161
use crate::bb02_async::block_on;
162+
use crate::workflow::testing::{Screen, TestingWorkflows};
157163
use alloc::boxed::Box;
158164
use bitbox02::testing::{
159165
mock, mock_memory, mock_sd, mock_unlocked, mock_unlocked_using_mnemonic, Data,
@@ -167,26 +173,44 @@ mod tests {
167173
// All good.
168174
mock(Data {
169175
sdcard_inserted: Some(true),
170-
ui_confirm_create: Some(Box::new(|params| {
171-
assert_eq!(params.body, "Mon 2020-09-28");
172-
true
173-
})),
174176
..Default::default()
175177
});
176178
mock_sd();
177179
mock_memory();
178180
mock_unlocked();
181+
182+
let mut mock_workflows = TestingWorkflows::new();
179183
assert_eq!(
180-
block_on(create(&pb::CreateBackupRequest {
181-
timestamp: EXPECTED_TIMESTMAP,
182-
timezone_offset: 18000,
183-
})),
184+
block_on(create(
185+
&mut mock_workflows,
186+
&pb::CreateBackupRequest {
187+
timestamp: EXPECTED_TIMESTMAP,
188+
timezone_offset: 18000,
189+
}
190+
)),
184191
Ok(Response::Success(pb::Success {}))
185192
);
186193
assert_eq!(EXPECTED_TIMESTMAP, bitbox02::memory::get_seed_birthdate());
194+
assert_eq!(
195+
mock_workflows.screens,
196+
vec![
197+
Screen::Confirm {
198+
title: "Is today?".into(),
199+
body: "Mon 2020-09-28".into(),
200+
longtouch: false
201+
},
202+
Screen::Status {
203+
title: "Backup created".into(),
204+
success: true
205+
}
206+
]
207+
);
187208

188209
assert_eq!(
189-
block_on(check(&pb::CheckBackupRequest { silent: true })),
210+
block_on(check(
211+
&mut TestingWorkflows::new(),
212+
&pb::CheckBackupRequest { silent: true }
213+
)),
190214
Ok(Response::CheckBackup(pb::CheckBackupResponse {
191215
id: "41233dfbad010723dbbb93514b7b81016b73f8aa35c5148e1b478f60d5750dce".into()
192216
}))
@@ -197,29 +221,10 @@ mod tests {
197221
/// should catch regressions when changing backup loading/verification in the firmware code.
198222
#[test]
199223
fn test_fixture() {
200-
static mut UI_COUNTER: u32 = 0;
201-
static EXPECTED_ID: &str =
224+
const EXPECTED_ID: &str =
202225
"577782fdfffbe314b23acaeefc39ad5e8641fba7e7dbe418a35956a879a67dd2";
203226
mock(Data {
204227
sdcard_inserted: Some(true),
205-
ui_confirm_create: Some(Box::new(|params| {
206-
match unsafe {
207-
UI_COUNTER += 1;
208-
UI_COUNTER
209-
} {
210-
1 => {
211-
assert_eq!(params.title, "Name?");
212-
assert_eq!(params.body, "My BitBox");
213-
true
214-
}
215-
2 => {
216-
assert_eq!(params.title, "ID?");
217-
assert_eq!(params.body, EXPECTED_ID);
218-
true
219-
}
220-
_ => panic!("unexpected UI dialog"),
221-
}
222-
})),
223228
..Default::default()
224229
});
225230
mock_sd();
@@ -241,13 +246,35 @@ mod tests {
241246
.unwrap();
242247
}
243248
// Check that the loaded seed matches the backup.
249+
let mut mock_workflows = TestingWorkflows::new();
244250
assert_eq!(
245-
block_on(check(&pb::CheckBackupRequest { silent: false })),
251+
block_on(check(
252+
&mut mock_workflows,
253+
&pb::CheckBackupRequest { silent: false }
254+
)),
246255
Ok(Response::CheckBackup(pb::CheckBackupResponse {
247256
id: EXPECTED_ID.into()
248257
}))
249258
);
250-
assert_eq!(unsafe { UI_COUNTER }, 2);
259+
assert_eq!(
260+
mock_workflows.screens,
261+
vec![
262+
Screen::Confirm {
263+
title: "Name?".into(),
264+
body: "My BitBox".into(),
265+
longtouch: false
266+
},
267+
Screen::Confirm {
268+
title: "ID?".into(),
269+
body: EXPECTED_ID.into(),
270+
longtouch: false
271+
},
272+
Screen::Status {
273+
title: "Backup valid".into(),
274+
success: true
275+
},
276+
]
277+
);
251278
}
252279

253280
#[test]
@@ -270,17 +297,19 @@ mod tests {
270297
// Create one backup.
271298
mock(Data {
272299
sdcard_inserted: Some(true),
273-
ui_confirm_create: Some(Box::new(|_params| true)),
274300
..Default::default()
275301
});
276302
mock_memory();
277303
mock_unlocked_using_mnemonic("purity concert above invest pigeon category peace tuition hazard vivid latin since legal speak nation session onion library travel spell region blast estate stay", "");
278304

279305
bitbox02::memory::set_device_name(DEVICE_NAME_1).unwrap();
280-
assert!(block_on(create(&pb::CreateBackupRequest {
281-
timestamp: EXPECTED_TIMESTAMP,
282-
timezone_offset: 18000,
283-
}))
306+
assert!(block_on(create(
307+
&mut TestingWorkflows::new(),
308+
&pb::CreateBackupRequest {
309+
timestamp: EXPECTED_TIMESTAMP,
310+
timezone_offset: 18000,
311+
}
312+
))
284313
.is_ok());
285314

286315
assert_eq!(
@@ -297,16 +326,18 @@ mod tests {
297326
// Create another backup.
298327
mock(Data {
299328
sdcard_inserted: Some(true),
300-
ui_confirm_create: Some(Box::new(|_params| true)),
301329
..Default::default()
302330
});
303331
mock_memory();
304332
mock_unlocked_using_mnemonic("goddess item rack improve shaft occur actress rib emerge salad rich blame model glare lounge stable electric height scrub scrub oyster now dinner oven", "");
305333
bitbox02::memory::set_device_name(DEVICE_NAME_2).unwrap();
306-
assert!(block_on(create(&pb::CreateBackupRequest {
307-
timestamp: EXPECTED_TIMESTAMP,
308-
timezone_offset: 18000,
309-
}))
334+
assert!(block_on(create(
335+
&mut TestingWorkflows::new(),
336+
&pb::CreateBackupRequest {
337+
timestamp: EXPECTED_TIMESTAMP,
338+
timezone_offset: 18000,
339+
}
340+
))
310341
.is_ok());
311342

312343
assert_eq!(

0 commit comments

Comments
 (0)