Skip to content

Commit 07085c9

Browse files
committed
rust/hww: protobuf plumbing and set device name call in Rust
1 parent 80f66da commit 07085c9

File tree

4 files changed

+127
-2
lines changed

4 files changed

+127
-2
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2020 Shift Crypto AG
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use alloc::vec::Vec;
16+
17+
use super::pb;
18+
use super::pb::request::Request;
19+
use super::pb::response::Response;
20+
use bitbox02::commander::Error;
21+
22+
/// Creates an Error response. Corresponds to commander.c:_report_error().
23+
fn make_error(err: bitbox02::commander::Error) -> Response {
24+
use Error::*;
25+
let err = match err {
26+
COMMANDER_OK => panic!("can't call this function with COMMANDER_OK"),
27+
COMMANDER_ERR_INVALID_INPUT => pb::Error {
28+
code: 101,
29+
message: "invalid input".into(),
30+
},
31+
COMMANDER_ERR_MEMORY => pb::Error {
32+
code: 102,
33+
message: "memory".into(),
34+
},
35+
COMMANDER_ERR_GENERIC => pb::Error {
36+
code: 103,
37+
message: "generic error".into(),
38+
},
39+
COMMANDER_ERR_USER_ABORT => pb::Error {
40+
code: 104,
41+
message: "aborted by the user".into(),
42+
},
43+
COMMANDER_ERR_INVALID_STATE => pb::Error {
44+
code: 105,
45+
message: "can't call this endpoint: wrong state".into(),
46+
},
47+
COMMANDER_ERR_DISABLED => pb::Error {
48+
code: 106,
49+
message: "function disabled".into(),
50+
},
51+
COMMANDER_ERR_DUPLICATE => pb::Error {
52+
code: 107,
53+
message: "duplicate entry".into(),
54+
},
55+
};
56+
Response::Error(err)
57+
}
58+
59+
/// Encodes a protobuf Response message.
60+
fn encode(response: Response) -> Vec<u8> {
61+
use prost::Message;
62+
let response = pb::Response {
63+
response: Some(response),
64+
};
65+
let mut out = Vec::<u8>::new();
66+
response.encode(&mut out).unwrap();
67+
out
68+
}
69+
70+
async fn api_set_device_name(
71+
pb::SetDeviceNameRequest { name }: &pb::SetDeviceNameRequest,
72+
) -> Response {
73+
use crate::workflow::confirm;
74+
let params = confirm::Params {
75+
title: "Name",
76+
body: &name,
77+
scrollable: true,
78+
..Default::default()
79+
};
80+
81+
if !confirm::confirm(&params).await {
82+
return make_error(Error::COMMANDER_ERR_USER_ABORT);
83+
}
84+
85+
if bitbox02::memory::set_device_name(&name).is_err() {
86+
return make_error(Error::COMMANDER_ERR_MEMORY);
87+
}
88+
89+
Response::Success(pb::Success {})
90+
}
91+
92+
/// Handle a protobuf api call.
93+
///
94+
/// Returns `None` if the call was not handled by Rust, in which case
95+
/// it should be handled by the C commander.
96+
async fn process_api(request: &Request) -> Option<Response> {
97+
match request {
98+
Request::DeviceName(ref request) => Some(api_set_device_name(request).await),
99+
_ => None,
100+
}
101+
}
102+
103+
/// Handle a protobuf api call. API calls not handled by Rust are
104+
/// handled by the C commander, which allows us to use Rust for new
105+
/// api calls and port the old calls step by step.
106+
///
107+
/// `input` is a hww.proto Request message, protobuf encoded.
108+
/// Returns a protobuf encoded hww.proto Response message.
109+
pub async fn process(input: Vec<u8>) -> Vec<u8> {
110+
use prost::Message;
111+
let request = match pb::Request::decode(&input[..]) {
112+
Ok(pb::Request {
113+
request: Some(request),
114+
}) => request,
115+
_ => return encode(make_error(Error::COMMANDER_ERR_INVALID_INPUT)),
116+
};
117+
match process_api(&request).await {
118+
Some(response) => encode(response),
119+
// Api call not handled in Rust -> handle it in C.
120+
_ => bitbox02::commander::commander(input),
121+
}
122+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@
1515
mod pb {
1616
include!("./shiftcrypto.bitbox02.rs");
1717
}
18+
19+
mod api;
20+
pub use api::process;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ pub(crate) async fn process(usb_in: Vec<u8>, usb_out: &mut Vec<u8>) -> Result<()
117117
}
118118
Some((&OP_NOISE_MSG, encrypted_msg)) => {
119119
let decrypted_msg = state.decrypt(encrypted_msg)?;
120-
let response = bitbox02::commander::commander(decrypted_msg);
120+
let response = super::api::process(decrypted_msg).await;
121121
state.encrypt(&response, usb_out)?;
122122
Ok(())
123123
}

src/rust/bitbox02/src/commander.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
pub type Error = bitbox02_sys::commander_error_t;
16+
pub use bitbox02_sys::commander_error_t as Error;
1717

1818
extern crate alloc;
1919
use alloc::vec::Vec;

0 commit comments

Comments
 (0)