From 5791bd17d08e743b927590a417ecb3e64c691660 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Wed, 17 Jan 2024 15:44:42 +0100 Subject: [PATCH] Add address confirmation and clean-up, rename some functions. --- ledger_device_sdk/src/nbgl.rs | 262 ++++++++++++++++++++-------------- 1 file changed, 158 insertions(+), 104 deletions(-) diff --git a/ledger_device_sdk/src/nbgl.rs b/ledger_device_sdk/src/nbgl.rs index 1b1941e4..c22b377c 100644 --- a/ledger_device_sdk/src/nbgl.rs +++ b/ledger_device_sdk/src/nbgl.rs @@ -39,6 +39,8 @@ struct NbglContext { icon: Option<&'static [u8]>, name: [u8; 100], info_contents: [[u8; 20]; 2], + review_confirm_string: [u8; 40], + review_reject_string: [u8; 40], review_pairs: [ledger_secure_sdk_sys::nbgl_layoutTagValue_t; 10], nb_pairs: u8, review_status: ReviewStatus, @@ -78,7 +80,131 @@ impl<'a> NbglUI<'a> { self } - fn settings() { + pub fn get_events>(&mut self) -> Event + where + Reply: From<>::Error>, + { + loop { + if let Some(event) = self.get_event::() { + return event; + } + } + } + + pub fn show_home>(&mut self) -> Event + where + Reply: From<>::Error>, + { + Self::display_home_cbk(); + return self.get_events(); + } + + pub fn review_transaction(&mut self, fields: &[Field]) -> bool { + unsafe { + let icon = nbgl_icon_details_t { + width: 64, + height: 64, + bpp: 2, + isFile: true, + bitmap: CTX.icon.unwrap().as_ptr(), + }; + + for (i, field) in fields.iter().enumerate() { + if i >= CTX.review_pairs.len() { + break; + } + CTX.review_pairs[i] = nbgl_layoutTagValue_t { + item: field.name.as_ptr() as *const ::core::ffi::c_char, + value: field.value.as_ptr() as *const ::core::ffi::c_char, + valueIcon: core::ptr::null(), + }; + } + + CTX.nb_pairs = if fields.len() < CTX.review_pairs.len() { + fields.len() + } else { + CTX.review_pairs.len() + } as u8; + + CTX.review_status = ReviewStatus::Pending; + + ledger_secure_sdk_sys::nbgl_useCaseReviewStart( + &icon as *const nbgl_icon_details_t, + "Review tx\0".as_ptr() as *const ::core::ffi::c_char, + "Subtitle\0".as_ptr() as *const ::core::ffi::c_char, + "Reject transaction\0".as_ptr() as *const ::core::ffi::c_char, + transmute((|| Self::display_static_review_cbk()) as fn()), + None, + ); + + return self.wait_review_result(); + } + } + + pub fn verify_address(&mut self, address: &str) -> bool { + unsafe { + let icon = nbgl_icon_details_t { + width: 64, + height: 64, + bpp: 2, + isFile: true, + bitmap: CTX.icon.unwrap().as_ptr(), + }; + + CTX.nb_pairs = 1; + CTX.review_pairs[0] = nbgl_layoutTagValue_t { + item: "\0".as_ptr() as *const ::core::ffi::c_char, // Unused + value: address.as_ptr() as *const ::core::ffi::c_char, + valueIcon: core::ptr::null(), + }; + CTX.review_status = ReviewStatus::Pending; + + ledger_secure_sdk_sys::nbgl_useCaseReviewStart( + &icon as *const nbgl_icon_details_t, + "Verify address\0".as_ptr() as *const ::core::ffi::c_char, + core::ptr::null(), + "Cancel\0".as_ptr() as *const ::core::ffi::c_char, + transmute((|| Self::display_address_confirmation_cbk()) as fn()), + None, + ); + + return self.wait_review_result(); + } + } + + fn get_event>(&mut self) -> Option> + where + Reply: From<>::Error>, + { + match &mut self.comm { + None => None, + Some(comm) => { + if let Event::Command(ins) = comm.next_event() { + return Some(Event::Command(ins)); + } + else + { + return None; + } + } + } + } + + fn wait_review_result(&mut self) -> bool { + loop { + self.get_event::(); + unsafe { + if CTX.review_status == ReviewStatus::Validate { + return true; + } + else if CTX.review_status == ReviewStatus::Reject { + return false; + } + } + } + } + + fn display_settings_cbk() { unsafe { let nav = |page: u8, content: *mut nbgl_pageContent_s| { if page == 0 { @@ -101,14 +227,14 @@ impl<'a> NbglUI<'a> { 0 as u8, 1 as u8, false as bool, - transmute((|| Self::home()) as fn()), + transmute((|| Self::display_home_cbk()) as fn()), transmute(nav as fn(u8, *mut nbgl_pageContent_s) -> bool), transmute((|| exit_app(12)) as fn()), ); } } - fn home() { + fn display_home_cbk() { unsafe { let icon = nbgl_icon_details_t { width: 64, @@ -123,41 +249,32 @@ impl<'a> NbglUI<'a> { &icon as *const nbgl_icon_details_t, core::ptr::null(), true as bool, - transmute((|| Self::settings()) as fn()), + transmute((|| Self::display_settings_cbk()) as fn()), transmute((|| exit_app(12)) as fn()), ); } } - pub fn show_home(&mut self) { - Self::home(); - } + fn display_review_result_cbk(confirm: bool) { - fn choice(confirm: bool) { - let show_home = || { - Self::home(); - }; - let result_string: *const ::core::ffi::c_char; unsafe { if confirm { CTX.review_status = ReviewStatus::Validate; - result_string = "TRANSACTION\nSIGNED\0".as_ptr() as *const ::core::ffi::c_char; + result_string = CTX.review_confirm_string.as_ptr() as *const ::core::ffi::c_char; } else { CTX.review_status = ReviewStatus::Reject; - result_string = "Transaction\nRejected\0".as_ptr() as *const ::core::ffi::c_char; + result_string = CTX.review_reject_string.as_ptr() as *const ::core::ffi::c_char; } - } - - unsafe { + ledger_secure_sdk_sys::nbgl_useCaseStatus( result_string, confirm, - transmute(show_home as fn())); + transmute((|| Self::display_home_cbk()) as fn())); } } - fn static_review() { + fn display_static_review_cbk() { unsafe { let tag_value_list: nbgl_layoutTagValueList_t = nbgl_layoutTagValueList_t { pairs: CTX.review_pairs.as_mut_ptr() as *mut nbgl_layoutTagValue_t, @@ -171,14 +288,19 @@ impl<'a> NbglUI<'a> { }; // Using this icon causes a crash - // let icon = nbgl_icon_details_t { - // width: 64, - // height: 64, - // bpp: 2, - // isFile: true, - // bitmap: CTX.icon.unwrap().as_ptr(), - // }; + let icon = nbgl_icon_details_t { + width: 32, + height: 32, + bpp: 2, + isFile: true, + bitmap: CTX.icon.unwrap().as_ptr(), + }; + let confirm_string = "TRANSACTION\nSIGNED\0"; + CTX.review_confirm_string[..confirm_string.len()].copy_from_slice(confirm_string.as_bytes()); + let reject_string = "Transaction\nRejected\0"; + CTX.review_reject_string[..reject_string.len()].copy_from_slice(reject_string.as_bytes()); + let info_long_press: nbgl_pageInfoLongPress_t = nbgl_pageInfoLongPress_t { text: "Validate tx\0".as_ptr() as *const ::core::ffi::c_char, icon: core::ptr::null(), @@ -191,91 +313,23 @@ impl<'a> NbglUI<'a> { &tag_value_list as *const nbgl_layoutTagValueList_t, &info_long_press as *const nbgl_pageInfoLongPress_t, "Reject tx\0".as_ptr() as *const ::core::ffi::c_char, - // None, - transmute((|confirm| Self::choice(confirm)) as fn(confirm: bool)), + transmute((|confirm| Self::display_review_result_cbk(confirm)) as fn(confirm: bool)), ); } } - - pub fn show_review_and_wait_validation(&mut self, fields: &[Field]) -> bool { - unsafe { - let icon = nbgl_icon_details_t { - width: 64, - height: 64, - bpp: 2, - isFile: true, - bitmap: CTX.icon.unwrap().as_ptr(), - }; - for (i, field) in fields.iter().enumerate() { - if i >= CTX.review_pairs.len() { - break; - } - CTX.review_pairs[i] = nbgl_layoutTagValue_t { - item: field.name.as_ptr() as *const ::core::ffi::c_char, - value: field.value.as_ptr() as *const ::core::ffi::c_char, - valueIcon: core::ptr::null(), - }; - } - - CTX.nb_pairs = if fields.len() < CTX.review_pairs.len() { - fields.len() - } else { - CTX.review_pairs.len() - } as u8; + fn display_address_confirmation_cbk() { + unsafe { - CTX.review_status = ReviewStatus::Pending; + let confirm_string = "ADDRESS\nVERIFIED\0"; + CTX.review_confirm_string[..confirm_string.len()].copy_from_slice(confirm_string.as_bytes()); + let reject_string = "Address verification\ncancelled\0"; + CTX.review_reject_string[..reject_string.len()].copy_from_slice(reject_string.as_bytes()); - ledger_secure_sdk_sys::nbgl_useCaseReviewStart( - &icon as *const nbgl_icon_details_t, - "Review tx\0".as_ptr() as *const ::core::ffi::c_char, - "Subtitle\0".as_ptr() as *const ::core::ffi::c_char, - "Reject transaction\0".as_ptr() as *const ::core::ffi::c_char, - transmute((|| Self::static_review()) as fn()), - None, + ledger_secure_sdk_sys::nbgl_useCaseAddressConfirmation( + CTX.review_pairs[0].value as *const ::core::ffi::c_char, + transmute((|confirm| Self::display_review_result_cbk(confirm)) as fn(confirm: bool)), ); - - loop { - self.get_event::(); - - if CTX.review_status == ReviewStatus::Validate { - debug_print("Validate\n"); - return true; - } - else if CTX.review_status == ReviewStatus::Reject { - debug_print("Reject\n"); - return false; - } - } - } - } - - fn get_event>(&mut self) -> Option> - where - Reply: From<>::Error>, - { - match &mut self.comm { - None => None, - Some(comm) => { - if let Event::Command(ins) = comm.next_event() { - return Some(Event::Command(ins)); - } - else - { - return None; - } - } - } - } - - pub fn get_events>(&mut self) -> Event - where - Reply: From<>::Error>, - { - loop { - if let Some(event) = self.get_event::() { - return event; - } } } }