Skip to content

Commit

Permalink
Add settings example.
Browse files Browse the repository at this point in the history
  • Loading branch information
agrojean-ledger committed May 20, 2024
1 parent 7f82152 commit 8d492d8
Show file tree
Hide file tree
Showing 37 changed files with 129 additions and 8 deletions.
2 changes: 1 addition & 1 deletion ledger_app.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[app]
build_directory = "./"
sdk = "Rust"
devices = ["nanos", "nanox", "nanos+", "stax"]
devices = ["nanos", "nanox", "nanos+", "stax", "flex"]

[tests]
pytest_directory = "./tests/"
19 changes: 15 additions & 4 deletions src/app_ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ use ledger_device_sdk::ui::bitmaps::{Glyph, BACK, CERTIFICATE, DASHBOARD_X};
use ledger_device_sdk::ui::gadgets::{EventOrPageIndex, MultiPageMenu, Page};

#[cfg(any(target_os = "stax", target_os = "flex"))]
use ledger_device_sdk::nbgl::{NbglGlyph, NbglHome};
use crate::settings::Settings;
#[cfg(any(target_os = "stax", target_os = "flex"))]
use ledger_device_sdk::nbgl::{NbglGlyph, NbglHomeAndSettings};

use crate::Instruction;

// use ledger_device_sdk::nvm::*;

#[cfg(not(any(target_os = "stax", target_os = "flex")))]
fn ui_about_menu(comm: &mut Comm) -> Event<Instruction> {
let pages = [
Expand Down Expand Up @@ -68,10 +72,17 @@ pub fn ui_menu_main(comm: &mut Comm) -> Event<Instruction> {
pub fn ui_menu_main(comm: &mut Comm) -> Event<Instruction> {
// Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph.
const FERRIS: NbglGlyph = NbglGlyph::from_include(include_gif!("crab_64x64.gif", NBGL));

let settings_strings = [["Display Memo", "Allow display of transaction memo."]];
let settings = Settings::default();
// Display the home screen.
NbglHome::new(comm)
NbglHomeAndSettings::new(comm)
.glyph(&FERRIS)
// .app_name("Boilerplate")
.infos("Boilerplate", env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS"))
.settings(settings.get_mut_ref(), &settings_strings)
.infos(
"Boilerplate",
env!("CARGO_PKG_VERSION"),
env!("CARGO_PKG_AUTHORS"),
)
.show()
}
11 changes: 10 additions & 1 deletion src/app_ui/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use ledger_device_sdk::ui::bitmaps::{CROSSMARK, EYE, VALIDATE_14};
#[cfg(not(any(target_os = "stax", target_os = "flex")))]
use ledger_device_sdk::ui::gadgets::{Field, MultiFieldReview};

#[cfg(any(target_os = "stax", target_os = "flex"))]
use crate::settings::Settings;
#[cfg(any(target_os = "stax", target_os = "flex"))]
use include_gif::include_gif;
#[cfg(any(target_os = "stax", target_os = "flex"))]
Expand Down Expand Up @@ -101,6 +103,13 @@ pub fn ui_display_tx(tx: &Tx) -> Result<bool, AppSW> {
"Sign transaction\nto send CRAB",
)
.glyph(&FERRIS);
Ok(review.show(&my_fields))

// If first setting switch is disabled do not display the transaction memo
let settings = Settings::default();
if settings.get_element(0) == 0 {
return Ok(review.show(&my_fields[0..2]));
} else {
return Ok(review.show(&my_fields));
}
}
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ mod handlers {
pub mod sign_tx;
}

mod settings;

use app_ui::menu::ui_menu_main;
use handlers::{
get_public_key::handler_get_public_key,
Expand Down
39 changes: 39 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use ledger_device_sdk::nvm::*;
use ledger_device_sdk::NVMData;

// This is necessary to store the object in NVM and not in RAM
const SETTINGS_SIZE: usize = 10;
#[link_section = ".nvm_data"]
static mut DATA: NVMData<AtomicStorage<[u8; SETTINGS_SIZE]>> =
NVMData::new(AtomicStorage::new(&[0u8; 10]));

#[derive(Clone, Copy)]
pub struct Settings;

impl Default for Settings {
fn default() -> Self {
Settings
}
}

impl Settings {
#[inline(never)]
pub fn get_mut_ref(&self) -> &mut AtomicStorage<[u8; SETTINGS_SIZE]> {
return unsafe { DATA.get_mut() };
}

pub fn get_element(&self, index: usize) -> u8 {
let settings = unsafe { DATA.get_mut() };
settings.get_ref()[index]
}

#[allow(unused)]
// Not used in this boilerplate, but can be used to set a value in the settings
pub fn set_element(&self, index: usize, value: u8) {
let mut updated_data: [u8; SETTINGS_SIZE] = unsafe { DATA.get_mut().get_ref().clone() };
updated_data[index] = value;
unsafe {
DATA.get_mut().update(&updated_data);
}
}
}
Binary file modified tests/snapshots/flex/test_app_mainmenu/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_app_mainmenu/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/flex/test_app_mainmenu/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_sign_tx_long_tx/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_sign_tx_refused/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_sign_tx_refused/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/flex/test_sign_tx_short_tx/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_long_tx/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_refused/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_refused/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_short_tx/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tests/test_app_mainmenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def test_app_mainmenu(firmware, navigator, test_name):
else:
instructions = [
NavInsID.USE_CASE_HOME_SETTINGS,
NavInsID.USE_CASE_SUB_SETTINGS_NEXT,
NavInsID.USE_CASE_SUB_SETTINGS_EXIT
]
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, instructions,
Expand Down
63 changes: 61 additions & 2 deletions tests/test_sign_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors
from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response
from ragger.error import ExceptionRAPDU
from ragger.navigator import NavInsID
from ragger.navigator import NavIns, NavInsID
from utils import ROOT_SCREENSHOT_PATH, check_signature_validity

# In this tests we check the behavior of the device when asked to sign a transaction
Expand All @@ -31,7 +31,15 @@ def test_sign_tx_short_tx(firmware, backend, navigator, test_name):
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo="For u EthDev"
).serialize()


# Enable display of transaction memo (NBGL devices only)
if not firmware.device.startswith("nano"):
navigator.navigate([NavInsID.USE_CASE_HOME_SETTINGS,
NavIns(NavInsID.TOUCH, (200, 113)),
NavInsID.USE_CASE_SUB_SETTINGS_EXIT],
screen_change_before_first_instruction=False,
screen_change_after_last_instruction=False)

# Send the sign device instruction.
# As it requires on-screen validation, the function is asynchronous.
# It will yield the result when the navigation is done
Expand All @@ -56,6 +64,49 @@ def test_sign_tx_short_tx(firmware, backend, navigator, test_name):
_, der_sig, _ = unpack_sign_tx_response(response)

assert check_signature_validity(public_key, der_sig, transaction)

# In this test se send to the device a transaction to sign and validate it on screen
# The transaction is short and will be sent in one chunk
# We will ensure that the displayed information is correct by using screenshots comparison
# The transaction memo should not be displayed as we have not enabled it in the app settings.
def test_sign_tx_short_tx_no_memo(firmware, backend, navigator, test_name):
if firmware.device.startswith("nano"):
pytest.skip("Skipping this test for Nano devices")

# Use the app interface instead of raw interface
client = BoilerplateCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/1'/0'/0/0"

# First we need to get the public key of the device in order to build the transaction
rapdu = client.get_public_key(path=path)
_, public_key, _, _ = unpack_get_public_key_response(rapdu.data)

# Create the transaction that will be sent to the device for signing
transaction = Transaction(
nonce=1,
coin="CRAB",
value=777,
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo="For u EthDev"
).serialize()

# Send the sign device instruction.
# As it requires on-screen validation, the function is asynchronous.
# It will yield the result when the navigation is done
with client.sign_tx(path=path, transaction=transaction):
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.WAIT_FOR_HOME_SCREEN],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)

# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _ = unpack_sign_tx_response(response)

assert check_signature_validity(public_key, der_sig, transaction)


# In this test se send to the device a transaction to sign and validate it on screen
Expand All @@ -79,6 +130,14 @@ def test_sign_tx_long_tx(firmware, backend, navigator, test_name):
"As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.")
).serialize()

# Enable display of transaction memo (NBGL devices only)
if not firmware.device.startswith("nano"):
navigator.navigate([NavInsID.USE_CASE_HOME_SETTINGS,
NavIns(NavInsID.TOUCH, (200, 113)),
NavInsID.USE_CASE_SUB_SETTINGS_EXIT],
screen_change_before_first_instruction=False,
screen_change_after_last_instruction=False)

with client.sign_tx(path=path, transaction=transaction):
if firmware.device.startswith("nano"):
Expand Down

0 comments on commit 8d492d8

Please sign in to comment.