Skip to content

Commit ac60219

Browse files
committed
Improve stax/flex ui using the streaming api
1 parent dc8f29f commit ac60219

File tree

7 files changed

+249
-215
lines changed

7 files changed

+249
-215
lines changed

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version := 3.30.0
1+
version := 3.34.0
22
ledger_app_builder = ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:$(version)
33
ledger_app_dev_tools = ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:$(version)
44

@@ -15,8 +15,8 @@ _release:
1515
cd app && \
1616
echo 'Building $(device) app' && \
1717
RUST_BACKTRACE=1 cargo ledger build $(device) -- -Z unstable-options && \
18-
cp ./target/$(device)/release/app.hex ../$(device).hex && \
19-
mv ./app_$(device).json ../$(device).json && \
18+
cp ./target/$(device)/release/alephium.hex ../$(device).hex && \
19+
mv ./target/$(device)/release/app_$(device).json ../$(device).json && \
2020
sed -i 's|target/$(device)/release/app.hex|$(device).hex|g;s|alph_16x16.gif|./app/alph_16x16.gif|g;s|alph_14x14.gif|./app/alph_14x14.gif|g;s|alph_32x32.gif|./app/alph_32x32.gif|g;s|alph_64x64.gif|./app/alph_64x64.gif|g' ../$(device).json \
2121
"
2222

app/src/ledger_sdk_stub/nbgl_review.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl NbglStreamingReview {
5959
let subtitle = CString::new(subtitle).unwrap();
6060

6161
if self.blind {
62-
if !show_blind_warning() {
62+
if !accept_blind_warning() {
6363
return false;
6464
}
6565
}
@@ -150,25 +150,14 @@ impl NbglStreamingReview {
150150
/// or review the risk. If the user chooses to review the risk, a second screen
151151
/// is displayed with the option to accept the risk or reject the transaction.
152152
/// Used in NbglReview and NbglStreamingReview.
153-
fn show_blind_warning() -> bool {
153+
fn accept_blind_warning() -> bool {
154154
const WARNING: NbglGlyph = NbglGlyph::from_include(include_gif!("Warning_64px.gif", NBGL));
155155

156-
let back_to_safety = NbglChoice::new().glyph(&WARNING).show(
157-
"Security risk detected",
158-
"It may not be safe to sign this transaction. To continue, you'll need to review the risk.",
159-
"Back to safety",
160-
"Review risk",
161-
);
162-
163-
if !back_to_safety {
164-
NbglChoice::new()
165-
.show(
166-
"The transaction cannot be trusted",
167-
"Your Ledger cannot decode this transaction. If you sign it, you could be authorizing malicious actions that can drain your wallet.\n\nLearn more: ledger.com/e8",
168-
"I accept the risk",
169-
"Reject transaction"
170-
)
171-
} else {
172-
false
173-
}
156+
!NbglChoice::new().glyph(&WARNING)
157+
.show(
158+
"Blind signing ahead",
159+
"This transaction's details are not fully verifiable. If you sign it, you could lose all your assets.",
160+
"Back to safety",
161+
"Continue anyway"
162+
)
174163
}

app/src/main.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
use crate::ui::display::MainPages;
66
use crate::ui::tx_reviewer::TxReviewer;
77
use handler::{handle_apdu, Ins};
8-
#[cfg(any(target_os = "stax", target_os = "flex"))]
9-
use include_gif::include_gif;
108
use ledger_device_sdk::io;
119
#[cfg(any(target_os = "stax", target_os = "flex"))]
12-
use ledger_device_sdk::nbgl::{init_comm, NbglGlyph, NbglHomeAndSettings};
10+
use ledger_device_sdk::nbgl::{init_comm, NbglHomeAndSettings};
1311
#[cfg(any(target_os = "stax", target_os = "flex"))]
1412
use settings::SETTINGS_DATA;
1513
use sign_tx_context::SignTxContext;
@@ -54,19 +52,25 @@ extern "C" fn sample_main() {
5452

5553
#[cfg(any(target_os = "stax", target_os = "flex"))]
5654
{
55+
use crate::ui::nbgl::APP_ICON;
5756
init_comm(&mut comm);
5857
let settings_strings = [["Blind signing", "Enable blind signing"]];
59-
const APP_ICON: NbglGlyph = NbglGlyph::from_include(include_gif!("alph_64x64.gif", NBGL));
58+
59+
let mut home_and_settings = NbglHomeAndSettings::new()
60+
.glyph(&APP_ICON)
61+
.settings(unsafe { SETTINGS_DATA.get_mut() }, &settings_strings)
62+
.infos(
63+
"Alephium",
64+
env!("CARGO_PKG_VERSION"),
65+
env!("CARGO_PKG_AUTHORS"),
66+
);
67+
6068
loop {
61-
let event = NbglHomeAndSettings::new()
62-
.glyph(&APP_ICON)
63-
.settings(unsafe { SETTINGS_DATA.get_mut() }, &settings_strings)
64-
.infos(
65-
"Alephium",
66-
env!("CARGO_PKG_VERSION"),
67-
env!("CARGO_PKG_AUTHORS"),
68-
)
69-
.show::<Ins>();
69+
let event = if !tx_reviewer.nbgl_reviewer.review_started {
70+
home_and_settings.show::<Ins>()
71+
} else {
72+
comm.next_event()
73+
};
7074
if let io::Event::Command(ins) = event {
7175
match handle_apdu(&mut comm, ins, &mut sign_tx_context, &mut tx_reviewer) {
7276
Ok(_) => comm.reply_ok(),

app/src/sign_tx_context.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ enum DecodeStep {
3030
// A streaming decoder is used to decode the transaction in chunks so that it can handle large transactions
3131
pub struct SignTxContext {
3232
pub path: [u32; PATH_LENGTH],
33-
tx_decoder: StreamingDecoder<UnsignedTx>,
33+
pub tx_decoder: StreamingDecoder<UnsignedTx>,
3434
current_step: DecodeStep,
3535
hasher: Blake2bHasher,
3636
temp_data: SwappingBuffer<'static, RAM_SIZE, NVM_DATA_SIZE>,
@@ -194,11 +194,16 @@ pub fn check_blind_signing() -> Result<(), ErrorCode> {
194194

195195
#[cfg(any(target_os = "stax", target_os = "flex"))]
196196
pub fn check_blind_signing() -> Result<(), ErrorCode> {
197-
use crate::ui::nbgl::nbgl_review_info;
197+
use crate::ui::nbgl::nbgl_review_warning;
198198

199199
if is_blind_signing_enabled() {
200200
return Ok(());
201201
}
202-
nbgl_review_info("Blind signing must be enabled in Settings");
202+
let _ = nbgl_review_warning(
203+
"This transaction cannot be clear-signed",
204+
"Enable blind signing in the settings to sign this transaction.",
205+
"Go to home", // The ledger rust sdk does not support going to settings.
206+
"Reject transaction",
207+
);
203208
Err(ErrorCode::BlindSigningDisabled)
204209
}

app/src/ui/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,14 @@ pub fn sign_hash_ui(path: &[u32], message: &[u8]) -> Result<([u8; 72], u32, u32)
4545

4646
#[cfg(any(target_os = "stax", target_os = "flex"))]
4747
{
48-
use crate::ui::nbgl::{nbgl_review_fields, nbgl_sync_review_status, ReviewType};
49-
use ledger_device_sdk::nbgl::{Field, TagValueList};
48+
use crate::ui::nbgl::nbgl_review_hash;
49+
use ledger_device_sdk::nbgl::NbglReviewStatus;
5050

51-
let fields = [Field {
52-
name: "Hash",
53-
value: hex_str,
54-
}];
55-
let values = TagValueList::new(&fields, 0, false, false);
56-
let approved = nbgl_review_fields("Review", "Hash", &values);
57-
if approved {
58-
nbgl_sync_review_status(ReviewType::Hash);
51+
if nbgl_review_hash(hex_str) {
52+
NbglReviewStatus::new().show(true);
5953
sign_hash(path, message)
6054
} else {
55+
NbglReviewStatus::new().show(false);
6156
Err(ErrorCode::UserCancelled)
6257
}
6358
}

app/src/ui/nbgl.rs

Lines changed: 83 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,101 @@
1-
extern crate alloc;
2-
use alloc::{vec, vec::Vec};
1+
use crate::error_code::ErrorCode;
2+
use crate::ledger_sdk_stub::nbgl_review::NbglStreamingReview;
3+
use include_gif::include_gif;
4+
use ledger_device_sdk::nbgl::{Field, NbglChoice, NbglGlyph, NbglReviewStatus, TransactionType};
35

4-
#[cfg(any(target_os = "stax", target_os = "flex"))]
5-
use alloc::ffi::CString;
6-
use core::ffi::c_char;
7-
use ledger_device_sdk::nbgl::*;
8-
use ledger_secure_sdk_sys::*;
6+
pub static APP_ICON: NbglGlyph = NbglGlyph::from_include(include_gif!("alph_64x64.gif", NBGL));
97

10-
pub enum ReviewType {
11-
Transaction,
12-
Hash,
8+
fn new_nbgl_review(tx_type: TransactionType, blind: bool) -> NbglStreamingReview {
9+
let reviewer = NbglStreamingReview::new().tx_type(tx_type).glyph(&APP_ICON);
10+
if blind {
11+
reviewer.blind()
12+
} else {
13+
reviewer
14+
}
1315
}
1416

15-
pub fn nbgl_review_fields(title: &str, subtitle: &str, fields: &TagValueList) -> bool {
16-
unsafe {
17-
let title = CString::new(title).unwrap();
18-
let subtitle = CString::new(subtitle).unwrap();
19-
let finish = CString::new("Click to continue").unwrap();
20-
let icon = nbgl_icon_details_t::default();
21-
let sync_ret = ux_sync_reviewLight(
22-
TYPE_TRANSACTION.into(),
23-
&fields.into() as *const nbgl_contentTagValueList_t,
24-
&icon as *const nbgl_icon_details_t,
25-
title.as_ptr() as *const c_char,
26-
subtitle.as_ptr() as *const c_char,
27-
finish.as_ptr() as *const c_char,
28-
);
29-
matches!(sync_ret, UX_SYNC_RET_APPROVED)
30-
}
17+
pub struct NbglReviewer {
18+
pub review_started: bool,
19+
reviewer: Option<NbglStreamingReview>,
3120
}
3221

33-
pub fn nbgl_sync_review_status(tpe: ReviewType) {
34-
unsafe {
35-
let status_type = match tpe {
36-
ReviewType::Transaction => STATUS_TYPE_TRANSACTION_SIGNED,
37-
ReviewType::Hash => STATUS_TYPE_OPERATION_SIGNED, // there is no `STATUS_TYPE_HASH` in ledger sdk
38-
};
39-
let _ = ux_sync_reviewStatus(status_type);
22+
impl NbglReviewer {
23+
pub fn new() -> NbglReviewer {
24+
NbglReviewer {
25+
review_started: false,
26+
reviewer: None,
27+
}
4028
}
41-
}
4229

43-
fn nbgl_generic_review(content: &NbglPageContent, button_str: &str) -> bool {
44-
unsafe {
45-
let (c_struct, content_type, action_callback) = content.into();
46-
let c_content_list: Vec<nbgl_content_t> = vec![nbgl_content_t {
47-
content: c_struct,
48-
contentActionCallback: action_callback,
49-
type_: content_type,
50-
}];
30+
pub fn reset(&mut self) {
31+
self.review_started = false;
32+
self.reviewer = None;
33+
}
5134

52-
let content_struct = nbgl_genericContents_t {
53-
callbackCallNeeded: false,
54-
__bindgen_anon_1: nbgl_genericContents_t__bindgen_ty_1 {
55-
contentsList: c_content_list.as_ptr(),
56-
},
57-
nbContents: 1,
58-
};
35+
#[inline]
36+
fn get_reviewer(&self) -> &NbglStreamingReview {
37+
assert!(self.reviewer.is_some());
38+
self.reviewer.as_ref().unwrap()
39+
}
5940

60-
let button_cstring = CString::new(button_str).unwrap();
41+
pub fn set_reviewer(&mut self, blind: bool) {
42+
assert!(self.reviewer.is_none());
43+
self.reviewer = Some(new_nbgl_review(TransactionType::Transaction, blind));
44+
}
6145

62-
let sync_ret = ux_sync_genericReview(
63-
&content_struct as *const nbgl_genericContents_t,
64-
button_cstring.as_ptr() as *const c_char,
65-
);
46+
pub fn start_review(&mut self, message: &str) -> Result<(), ErrorCode> {
47+
if self.get_reviewer().start(message, "") {
48+
self.review_started = true;
49+
Ok(())
50+
} else {
51+
NbglReviewStatus::new().show(false);
52+
Err(ErrorCode::UserCancelled)
53+
}
54+
}
55+
56+
pub fn continue_review<'a>(&self, fields: &'a [Field<'a>]) -> Result<(), ErrorCode> {
57+
if self.get_reviewer().continue_review(fields) {
58+
Ok(())
59+
} else {
60+
NbglReviewStatus::new().show(false);
61+
Err(ErrorCode::UserCancelled)
62+
}
63+
}
6664

67-
// Return true if the user approved the transaction, false otherwise.
68-
matches!(sync_ret, ledger_secure_sdk_sys::UX_SYNC_RET_APPROVED)
65+
pub fn finish_review(&self, message: &str) -> Result<(), ErrorCode> {
66+
if self.get_reviewer().finish(message) {
67+
NbglReviewStatus::new().show(true);
68+
Ok(())
69+
} else {
70+
NbglReviewStatus::new().show(false);
71+
Err(ErrorCode::UserCancelled)
72+
}
6973
}
7074
}
7175

72-
pub fn nbgl_review_warning(message: &str) -> bool {
73-
let content = NbglPageContent::InfoButton(InfoButton::new(
74-
message,
75-
None,
76-
"Continue",
77-
TuneIndex::TapCasual,
78-
));
79-
nbgl_generic_review(&content, "Reject")
76+
pub fn nbgl_review_hash(hash: &str) -> bool {
77+
let reviewer = new_nbgl_review(TransactionType::Operation, false);
78+
if !reviewer.start("Review Hash", "") {
79+
return false;
80+
}
81+
let fields = [Field {
82+
name: "Hash",
83+
value: hash,
84+
}];
85+
if !reviewer.continue_review(&fields) {
86+
return false;
87+
}
88+
reviewer.finish("Sign Hash")
8089
}
8190

82-
pub fn nbgl_review_info(message: &str) {
83-
let content = NbglPageContent::CenteredInfo(CenteredInfo::new(
84-
message,
85-
"",
86-
"",
87-
None,
88-
false,
89-
CenteredInfoStyle::NormalInfo,
90-
0,
91-
));
92-
let _ = nbgl_generic_review(&content, "Tap to continue");
91+
pub fn nbgl_review_warning(
92+
message: &str,
93+
sub_message: &str,
94+
confirm_text: &str,
95+
cancel_text: &str,
96+
) -> bool {
97+
const WARNING: NbglGlyph = NbglGlyph::from_include(include_gif!("Warning_64px.gif", NBGL));
98+
NbglChoice::new()
99+
.glyph(&WARNING)
100+
.show(message, sub_message, confirm_text, cancel_text)
93101
}

0 commit comments

Comments
 (0)