Skip to content

Commit

Permalink
Merge pull request #170 from LedgerHQ/add_streaming_review
Browse files Browse the repository at this point in the history
Add streaming review support in NBGL module
  • Loading branch information
agrojean-ledger authored Jul 17, 2024
2 parents 3c22c1c + eed4139 commit 1e7b585
Show file tree
Hide file tree
Showing 10 changed files with 1,116 additions and 1,370 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions ledger_device_sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ledger_device_sdk"
version = "1.11.1"
version = "1.12.0"
authors = ["yhql", "yogh333", "agrojean-ledger", "kingofpayne"]
edition = "2021"
license.workspace = true
Expand All @@ -23,10 +23,10 @@ numtoa = "0.2.4"
const-zero = "0.1.1"

[target.'cfg(target_os="nanos")'.dependencies]
ledger_secure_sdk_sys = {path = "../ledger_secure_sdk_sys", version = "1.4.2"}
ledger_secure_sdk_sys = {path = "../ledger_secure_sdk_sys", version = "1.4.3"}

[target.'cfg(not(target_os="nanos"))'.dependencies]
ledger_secure_sdk_sys = {path = "../ledger_secure_sdk_sys", version = "1.4.2", features = ["heap"]}
ledger_secure_sdk_sys = {path = "../ledger_secure_sdk_sys", version = "1.4.3", features = ["heap"]}

[features]
speculos = []
Expand Down
8 changes: 7 additions & 1 deletion ledger_device_sdk/examples/nbgl_review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ use ledger_device_sdk::io::*;
use ledger_device_sdk::nbgl::{init_comm, Field, NbglGlyph, NbglReview};
use ledger_secure_sdk_sys::*;

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
exit_app(1);
}

#[no_mangle]
extern "C" fn sample_main() {
unsafe {
Expand Down Expand Up @@ -46,7 +51,8 @@ extern "C" fn sample_main() {
"To send CRAB",
"Sign transaction\nto send CRAB",
)
.glyph(&FERRIS);
.glyph(&FERRIS)
.blind();

review.show(&my_fields);
}
66 changes: 66 additions & 0 deletions ledger_device_sdk/examples/nbgl_streaming_review.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#![no_std]
#![no_main]

// Force boot section to be embedded in
use ledger_device_sdk as _;

use include_gif::include_gif;
use ledger_device_sdk::io::*;
use ledger_device_sdk::nbgl::{init_comm, Field, NbglGlyph, NbglStreamingReview, TransactionType};
use ledger_secure_sdk_sys::*;

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
exit_app(1);
}

#[no_mangle]
extern "C" fn sample_main() {
unsafe {
nbgl_refreshReset();
}

let mut comm = Comm::new();
// Initialize reference to Comm instance for NBGL
// API calls.
init_comm(&mut comm);

// Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph.
const FERRIS: NbglGlyph =
NbglGlyph::from_include(include_gif!("examples/crab_64x64.gif", NBGL));

let mut review: NbglStreamingReview = NbglStreamingReview::new()
.glyph(&FERRIS)
.tx_type(TransactionType::Message);

review.start("Example Title", "Example Subtitle");

let fields = [
Field {
name: "Name1",
value: "Value1",
},
Field {
name: "Name2",
value: "Value2",
},
Field {
name: "Name3",
value: "Value3",
},
Field {
name: "Name4",
value: "Value4",
},
Field {
name: "Name5",
value: "Value5",
},
];

for i in 0..fields.len() {
review.continue_review(&fields[i..i + 1]);
}

review.finish("Sign to send token\n");
}
199 changes: 196 additions & 3 deletions ledger_device_sdk/src/nbgl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,55 @@ impl<'a> Into<nbgl_icon_details_t> for &NbglGlyph<'a> {
}
}

pub enum TransactionType {
Transaction,
Message,
Operation,
}

impl TransactionType {
pub fn to_c_type(&self, blind: bool, skippable: bool) -> nbgl_operationType_t {
let mut tx_type = match self {
TransactionType::Transaction => TYPE_TRANSACTION.into(),
TransactionType::Message => TYPE_MESSAGE.into(),
TransactionType::Operation => TYPE_OPERATION.into(),
};
if blind {
tx_type |= BLIND_OPERATION;
}
if skippable {
tx_type |= SKIPPABLE_OPERATION;
}
tx_type
}

pub fn to_message(&self, success: bool) -> nbgl_reviewStatusType_t {
match self {
TransactionType::Transaction => {
if success {
STATUS_TYPE_TRANSACTION_SIGNED
} else {
STATUS_TYPE_TRANSACTION_REJECTED
}
}
TransactionType::Message => {
if success {
STATUS_TYPE_MESSAGE_SIGNED
} else {
STATUS_TYPE_MESSAGE_REJECTED
}
}
TransactionType::Operation => {
if success {
STATUS_TYPE_OPERATION_SIGNED
} else {
STATUS_TYPE_OPERATION_REJECTED
}
}
}
}
}

/// Initialize the global COMM_REF variable with the provided Comm instance.
/// This function should be called from the main function of the application.
/// The COMM_REF variable is used by the NBGL API to detect touch events and
Expand Down Expand Up @@ -290,6 +339,8 @@ pub struct NbglReview<'a> {
subtitle: CString,
finish_title: CString,
glyph: Option<&'a NbglGlyph<'a>>,
tx_type: TransactionType,
blind: bool,
}

impl<'a> NbglReview<'a> {
Expand All @@ -299,6 +350,19 @@ impl<'a> NbglReview<'a> {
subtitle: CString::new("").unwrap(),
finish_title: CString::new("").unwrap(),
glyph: None,
tx_type: TransactionType::Transaction,
blind: false,
}
}

pub fn tx_type(self, tx_type: TransactionType) -> NbglReview<'a> {
NbglReview { tx_type, ..self }
}

pub fn blind(self) -> NbglReview<'a> {
NbglReview {
blind: true,
..self
}
}

Expand Down Expand Up @@ -358,7 +422,7 @@ impl<'a> NbglReview<'a> {

// Show the review on the device.
let sync_ret = ledger_secure_sdk_sys::ux_sync_review(
TYPE_TRANSACTION.into(),
self.tx_type.to_c_type(self.blind, false),
&tag_value_list as *const nbgl_contentTagValueList_t,
&icon as *const nbgl_icon_details_t,
self.title.as_ptr() as *const c_char,
Expand All @@ -369,11 +433,11 @@ impl<'a> NbglReview<'a> {
// Return true if the user approved the transaction, false otherwise.
match sync_ret {
ledger_secure_sdk_sys::UX_SYNC_RET_APPROVED => {
ledger_secure_sdk_sys::ux_sync_reviewStatus(STATUS_TYPE_TRANSACTION_SIGNED);
ledger_secure_sdk_sys::ux_sync_reviewStatus(self.tx_type.to_message(true));
return true;
}
_ => {
ledger_secure_sdk_sys::ux_sync_reviewStatus(STATUS_TYPE_TRANSACTION_REJECTED);
ledger_secure_sdk_sys::ux_sync_reviewStatus(self.tx_type.to_message(false));
return false;
}
}
Expand Down Expand Up @@ -749,6 +813,10 @@ impl From<&NbglPageContent>
}
}

/// A wrapper around the synchronous NBGL ux_sync_genericReview C API binding.
/// Used to display custom built review screens. User can add different kind of
/// contents (CenteredInfo, InfoLongPress, InfoButton, TagValueList, TagValueConfirm, InfosList)
/// to the review screen using the add_content method.
pub struct NbglGenericReview {
content_list: Vec<NbglPageContent>,
}
Expand Down Expand Up @@ -821,6 +889,131 @@ impl NbglGenericReview {
}
}

/// A wrapper around the synchronous NBGL ux_sync_reviewStreaming (start, continue and finish)
/// C API binding. Used to display streamed transaction review screens.
pub struct NbglStreamingReview {
icon: nbgl_icon_details_t,
tx_type: TransactionType,
blind: bool,
}

impl NbglStreamingReview {
pub fn new() -> NbglStreamingReview {
NbglStreamingReview {
icon: nbgl_icon_details_t::default(),
tx_type: TransactionType::Transaction,
blind: false,
}
}

pub fn tx_type(self, tx_type: TransactionType) -> NbglStreamingReview {
NbglStreamingReview { tx_type, ..self }
}

pub fn blind(self) -> NbglStreamingReview {
NbglStreamingReview {
blind: true,
..self
}
}

pub fn glyph(self, glyph: &NbglGlyph) -> NbglStreamingReview {
NbglStreamingReview {
icon: glyph.into(),
..self
}
}

pub fn start(&mut self, title: &str, subtitle: &str) -> bool {
unsafe {
let title = CString::new(title).unwrap();
let subtitle = CString::new(subtitle).unwrap();

let sync_ret = ux_sync_reviewStreamingStart(
self.tx_type.to_c_type(self.blind, false),
&self.icon as *const nbgl_icon_details_t,
title.as_ptr() as *const c_char,
subtitle.as_ptr() as *const c_char,
);

// Return true if the user approved the transaction, false otherwise.
match sync_ret {
UX_SYNC_RET_APPROVED => {
return true;
}
_ => {
ux_sync_reviewStatus(self.tx_type.to_message(false));
return false;
}
}
}
}

pub fn continue_review(&mut self, fields: &[Field]) -> bool {
unsafe {
let v: Vec<CField> = fields
.iter()
.map(|f| CField {
name: CString::new(f.name).unwrap(),
value: CString::new(f.value).unwrap(),
})
.collect();

// Fill the tag_value_array with the fields converted to nbgl_contentTagValue_t
let mut tag_value_array: Vec<nbgl_contentTagValue_t> = Vec::new();
for field in v.iter() {
let val = nbgl_contentTagValue_t {
item: field.name.as_ptr() as *const i8,
value: field.value.as_ptr() as *const i8,
..Default::default()
};
tag_value_array.push(val);
}

// Create the tag_value_list with the tag_value_array.
let tag_value_list = nbgl_contentTagValueList_t {
pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t,
nbPairs: fields.len() as u8,
..Default::default()
};

let sync_ret = ux_sync_reviewStreamingContinue(
&tag_value_list as *const nbgl_contentTagValueList_t,
);

// Return true if the user approved the transaction, false otherwise.
match sync_ret {
UX_SYNC_RET_APPROVED => {
return true;
}
_ => {
ux_sync_reviewStatus(self.tx_type.to_message(false));
return false;
}
}
}
}

pub fn finish(&mut self, finish_title: &str) -> bool {
unsafe {
let finish_title = CString::new(finish_title).unwrap();
let sync_ret = ux_sync_reviewStreamingFinish(finish_title.as_ptr() as *const c_char);

// Return true if the user approved the transaction, false otherwise.
match sync_ret {
ledger_secure_sdk_sys::UX_SYNC_RET_APPROVED => {
ux_sync_reviewStatus(self.tx_type.to_message(true));
return true;
}
_ => {
ux_sync_reviewStatus(self.tx_type.to_message(false));
return false;
}
}
}
}
}

/// A wrapper around the synchronous NBGL ux_sync_addressReview C API binding.
/// Used to display address confirmation screens.
pub struct NbglAddressReview<'a> {
Expand Down
2 changes: 1 addition & 1 deletion ledger_secure_sdk_sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ledger_secure_sdk_sys"
version = "1.4.2"
version = "1.4.3"
authors = ["yhql", "agrojean-ledger"]
edition = "2021"
license.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion ledger_secure_sdk_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ fn clone_sdk(device: &Device) -> PathBuf {
),
Device::Stax => (
Path::new("https://github.com/LedgerHQ/ledger-secure-sdk"),
"API_LEVEL_15",
"API_LEVEL_21",
),
Device::Flex => (
Path::new("https://github.com/LedgerHQ/ledger-secure-sdk"),
Expand Down
Loading

0 comments on commit 1e7b585

Please sign in to comment.