Skip to content

Commit

Permalink
Merge branch 'paymentreq'
Browse files Browse the repository at this point in the history
  • Loading branch information
benma committed Aug 27, 2024
2 parents ff3599f + 459a523 commit e19b803
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 25 deletions.
16 changes: 8 additions & 8 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/payment_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use super::script::serialize_varint;
use pb::btc_payment_request_request::{memo, Memo};
use pb::btc_sign_init_request::FormatUnit;

use crate::workflow::{confirm, transaction};
use crate::workflow::{confirm, transaction, verify_message};

use sha2::{Digest, Sha256};

Expand All @@ -40,7 +40,7 @@ struct Identity {

const IDENTITIES: &[Identity] = &[
Identity {
name: "Pocket Bitcoin",
name: "POCKET",
public_key: b"\x02\x29\x02\xb4\xed\xe4\x82\xa9\x07\xce\x16\xa1\xc6\x34\x14\x5e\x72\x8f\x1d\xe4\xf2\x49\x04\x3a\x8b\xe4\x7d\xf2\x7d\xb9\x32\x0c\x2c",
},
#[cfg(feature = "testing")]
Expand Down Expand Up @@ -74,20 +74,20 @@ pub async fn user_verify(
Memo {
memo: Some(memo::Memo::TextMemo(text_memo)),
} => {
if !util::ascii::is_printable_ascii(&text_memo.note, util::ascii::Charset::All) {
if !util::ascii::is_printable_ascii(
&text_memo.note,
util::ascii::Charset::AllNewline,
) {
return Err(Error::InvalidInput);
}
confirm::confirm(&confirm::Params {
title: "",
body: &format!(
"Memo from {}: {}",
payment_request.recipient_name, text_memo.note,
),
scrollable: true,
body: &format!("Memo from\n\n{}", payment_request.recipient_name),
accept_is_nextarrow: true,
..Default::default()
})
.await?;
verify_message::verify("Memo", "Memo", text_memo.note.as_bytes(), false).await?;
}
_ => return Err(Error::InvalidInput),
}
Expand Down
3 changes: 2 additions & 1 deletion src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub async fn process(request: &pb::BtcSignMessageRequest) -> Result<Response, Er
};
confirm::confirm(&confirm_params).await?;

verify_message::verify(&request.msg).await?;
verify_message::verify("Sign message", "Sign", &request.msg, true).await?;

// See
// https://github.com/spesmilo/electrum/blob/84dc181b6e7bb20e88ef6b98fb8925c5f645a765/electrum/ecc.py#L355-L358.
Expand Down Expand Up @@ -303,6 +303,7 @@ mod tests {
3 => {
assert_eq!(params.title, "Sign message");
assert_eq!(params.body.as_bytes(), MESSAGE);
assert!(params.longtouch);
false
}
_ => panic!("too many user confirmations"),
Expand Down
30 changes: 23 additions & 7 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3178,14 +3178,14 @@ mod tests {
{
let mut tx = transaction.borrow_mut();
// An additional confirmation for the text memo.
tx.total_confirmations += 1;
tx.total_confirmations += 3;
let payment_request_output_index = 1;
let output_value = tx.outputs[payment_request_output_index].value;
let mut payment_request = pb::BtcPaymentRequestRequest {
recipient_name: "Test Merchant".into(),
memos: vec![Memo {
memo: Some(memo::Memo::TextMemo(memo::TextMemo {
note: "Test memo".into(),
note: "Test memo line1\nTest memo line2".into(),
})),
}],
nonce: vec![],
Expand Down Expand Up @@ -3222,12 +3222,12 @@ mod tests {
assert_eq!(amount, "12.34567890 BTC");
true
}
4 => {
6 => {
assert_eq!(address, "bc1qxvenxvenxvenxvenxvenxvenxvenxven2ymjt8");
assert_eq!(amount, "0.00006000 BTC");
true
}
5 => {
7 => {
assert_eq!(
address,
"bc1qg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zqd8sxw4"
Expand All @@ -3243,7 +3243,7 @@ mod tests {
UI_COUNTER += 1;
UI_COUNTER
} {
7 => {
9 => {
assert_eq!(total, "13.39999900 BTC");
assert_eq!(fee, "0.05419010 BTC");
true
Expand All @@ -3257,10 +3257,26 @@ mod tests {
UI_COUNTER
} {
3 => {
assert_eq!(params.body, "Memo from Test Merchant: Test memo");
assert_eq!(params.body, "Memo from\n\nTest Merchant");
assert!(params.accept_is_nextarrow);
assert!(!params.longtouch);
true
}
6 => {
4 => {
assert_eq!(params.title, "Memo 1/2");
assert_eq!(params.body, "Test memo line1");
assert!(params.accept_is_nextarrow);
assert!(!params.longtouch);
true
}
5 => {
assert_eq!(params.title, "Memo 2/2");
assert_eq!(params.body, "Test memo line2");
assert!(params.accept_is_nextarrow);
assert!(!params.longtouch);
true
}
8 => {
assert_eq!(params.title, "Warning");
assert_eq!(params.body, "There are 2\nchange outputs.\nProceed?");
true
Expand Down
3 changes: 2 additions & 1 deletion src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub async fn process(request: &pb::EthSignMessageRequest) -> Result<Response, Er
// abort errors.
super::pubrequest::process(&pub_request).await?;

verify_message::verify(&request.msg).await?;
verify_message::verify("Sign message", "Sign", &request.msg, true).await?;

// Construct message to be signed. There is no standard for this. We match what MyEtherWallet,
// Trezor, etc. do, e.g.:
Expand Down Expand Up @@ -121,6 +121,7 @@ mod tests {
2 => {
assert_eq!(params.title, "Sign message");
assert_eq!(params.body.as_bytes(), MESSAGE);
assert!(params.longtouch);
true
}
_ => panic!("too many user confirmations"),
Expand Down
27 changes: 19 additions & 8 deletions src/rust/bitbox02-rust/src/workflow/verify_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,23 @@ impl core::convert::From<confirm::UserAbort> for Error {
}
}

/// Verify a message to be signed.
/// Verify a message.
///
/// If the bytes are all printable ascii chars, the message is
/// confirmed one line at a time (the str is split into lines).
///
/// Otherwise, it is displayed as hex.
pub async fn verify(msg: &[u8]) -> Result<(), Error> {
///
/// title_long is shown if it is only one line/screen. title_short is shown if there are multiple
/// line screens, suffixed with the progress label (e.g. 1/3).
///
/// is_final if this is the final step in a workflow. In this case,
pub async fn verify(
title_long: &str,
title_short: &str,
msg: &[u8],
is_final: bool,
) -> Result<(), Error> {
if ascii::is_printable_ascii(msg, ascii::Charset::AllNewline) {
// The message is all ascii and printable.
let msg = core::str::from_utf8(msg).unwrap();
Expand All @@ -47,28 +57,29 @@ pub async fn verify(msg: &[u8]) -> Result<(), Error> {
for (i, &page) in pages.iter().enumerate() {
let is_last = i == pages.len() - 1;
let title = if pages.len() == 1 {
"Sign message".into()
title_long.into()
} else {
format!("Sign {}/{}", i + 1, pages.len())
format!("{} {}/{}", title_short, i + 1, pages.len())
};
let params = confirm::Params {
title: &title,
body: page,
scrollable: true,
accept_is_nextarrow: !is_last,
longtouch: is_last,
accept_is_nextarrow: true, // longtouch takes priority over this if enabled
longtouch: is_last && is_final,
..Default::default()
};
confirm::confirm(&params).await?;
}
Ok(())
} else {
let params = confirm::Params {
title: "Sign message\ndata (hex)",
title: &format!("{}\ndata (hex)", title_long),
body: &hex::encode(msg),
scrollable: true,
display_size: msg.len(),
longtouch: true,
accept_is_nextarrow: true, // longtouch takes priority over this if enabled
longtouch: is_final,
..Default::default()
};
confirm::confirm(&params).await?;
Expand Down

0 comments on commit e19b803

Please sign in to comment.