diff --git a/Makefile b/Makefile index fa4ca11a..9f9021c8 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ ICON_NANOS = icons/nanos_app_tron.gif ICON_NANOX = icons/nanox_app_tron.gif ICON_NANOSP = icons/nanox_app_tron.gif ICON_STAX = icons/stax_app_tron.gif +ICON_FLEX = icons/flex_app_tron.gif ENABLE_BLUETOOTH = 1 ENABLE_SWAP = 1 diff --git a/VERSION b/VERSION index 8f0916f7..a918a2aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/glyphs/stax_app_tron_64px.gif b/glyphs/app_tron_64px.gif similarity index 100% rename from glyphs/stax_app_tron_64px.gif rename to glyphs/app_tron_64px.gif diff --git a/icons/flex_app_tron.gif b/icons/flex_app_tron.gif new file mode 100644 index 00000000..e51d86b8 Binary files /dev/null and b/icons/flex_app_tron.gif differ diff --git a/ledger_app.toml b/ledger_app.toml index c264aa9d..7329320d 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -1,7 +1,7 @@ [app] build_directory = "./" sdk = "C" -devices = ["nanos", "nanox", "nanos+", "stax"] +devices = ["nanos", "nanox", "nanos+", "stax", "flex"] [tests] pytest_directory = "./tests/" diff --git a/src/ui/ui_idle_menu_nbgl.c b/src/ui/ui_idle_menu_nbgl.c index 47f64659..8fca9c07 100644 --- a/src/ui/ui_idle_menu_nbgl.c +++ b/src/ui/ui_idle_menu_nbgl.c @@ -31,59 +31,28 @@ enum { #define NB_INFO_FIELDS 3 static const char* const infoTypes[] = {"Version", "Developer", "Copyright"}; -static const char* const infoContents[] = {APPVERSION, "Klever", "(c) 2023 Ledger"}; +static const char* const infoContents[] = {APPVERSION, "Klever", "(c) 2024 Ledger"}; #define NB_SETTINGS_SWITCHES 3 #define SETTING_IDX(token) (token - SWITCH_ALLOW_TX_DATA_TOKEN) static uint8_t settings[NB_SETTINGS_SWITCHES] = {S_DATA_ALLOWED, S_CUSTOM_CONTRACT, S_SIGN_BY_HASH}; -static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES]; - -static void displaySettingsMenu(void); -static void settingsControlsCallback(int token, uint8_t index); -static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t* content); +static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES] = {0}; void onQuitCallback(void) { os_sched_exit(-1); } -static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t* content) { - if (page == 0) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = infoTypes; - content->infosList.infoContents = infoContents; - } else if (page == 1) { - switches[0].text = "Transactions data"; - switches[0].subText = "Allow extra data in\ntransactions"; - switches[0].token = SWITCH_ALLOW_TX_DATA_TOKEN; - switches[0].tuneId = TUNE_TAP_CASUAL; - switches[0].initState = (HAS_SETTING(S_DATA_ALLOWED)) ? ON_STATE : OFF_STATE; - switches[1].text = "Custom contracts"; - switches[1].subText = "Allow unverified contracts"; - switches[1].token = SWITCH_ALLOW_CSTM_CONTRACTS_TOKEN; - switches[1].tuneId = TUNE_TAP_CASUAL; - switches[1].initState = (HAS_SETTING(S_CUSTOM_CONTRACT)) ? ON_STATE : OFF_STATE; - switches[2].text = "Blind signing"; - switches[2].subText = "Allow transaction blind signing"; - switches[2].token = SWITCH_ALLOW_HASH_TX_TOKEN; - switches[2].tuneId = TUNE_TAP_CASUAL; - switches[2].initState = (HAS_SETTING(S_SIGN_BY_HASH)) ? ON_STATE : OFF_STATE; - content->type = SWITCHES_LIST; - content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; - content->switchesList.switches = (nbgl_layoutSwitch_t*) switches; - } else { - return false; - } - return true; -} - -static void settingsControlsCallback(int token, uint8_t index) { +static void settingsControlsCallback(int token, uint8_t index, int page) { UNUSED(index); + UNUSED(page); switch (token) { case SWITCH_ALLOW_TX_DATA_TOKEN: case SWITCH_ALLOW_CSTM_CONTRACTS_TOKEN: case SWITCH_ALLOW_HASH_TX_TOKEN: SETTING_TOGGLE(settings[SETTING_IDX(token)]); + switches[0].initState = (HAS_SETTING(S_DATA_ALLOWED)) ? ON_STATE : OFF_STATE; + switches[1].initState = (HAS_SETTING(S_CUSTOM_CONTRACT)) ? ON_STATE : OFF_STATE; + switches[2].initState = (HAS_SETTING(S_SIGN_BY_HASH)) ? ON_STATE : OFF_STATE; break; default: PRINTF("Should not happen !"); @@ -91,22 +60,48 @@ static void settingsControlsCallback(int token, uint8_t index) { } } -static void displaySettingsMenu(void) { - nbgl_useCaseSettings("Tron settings", - 0, - 2, - false, - ui_idle, - settingsNavCallback, - settingsControlsCallback); -} +// info menu definition +static const nbgl_contentInfoList_t infoList = { + .nbInfos = NB_INFO_FIELDS, + .infoTypes = infoTypes, + .infoContents = infoContents, +}; +// settings menu definition +#define SETTING_CONTENTS_NB 1 +static const nbgl_content_t contents[SETTING_CONTENTS_NB] = { + {.type = SWITCHES_LIST, + .content.switchesList.nbSwitches = NB_SETTINGS_SWITCHES, + .content.switchesList.switches = switches, + .contentActionCallback = settingsControlsCallback}}; + +static const nbgl_genericContents_t settingContents = {.callbackCallNeeded = false, + .contentsList = contents, + .nbContents = SETTING_CONTENTS_NB}; void ui_idle(void) { - nbgl_useCaseHome("Tron", - &C_stax_app_tron_64px, - NULL, - true, - displaySettingsMenu, - onQuitCallback); + switches[0].text = "Transactions data"; + switches[0].subText = "Allow extra data in\ntransactions"; + switches[0].token = SWITCH_ALLOW_TX_DATA_TOKEN; + switches[0].tuneId = TUNE_TAP_CASUAL; + switches[0].initState = (HAS_SETTING(S_DATA_ALLOWED)) ? ON_STATE : OFF_STATE; + switches[1].text = "Custom contracts"; + switches[1].subText = "Allow unverified contracts"; + switches[1].token = SWITCH_ALLOW_CSTM_CONTRACTS_TOKEN; + switches[1].tuneId = TUNE_TAP_CASUAL; + switches[1].initState = (HAS_SETTING(S_CUSTOM_CONTRACT)) ? ON_STATE : OFF_STATE; + switches[2].text = "Blind signing"; + switches[2].subText = "Allow transaction blind signing"; + switches[2].token = SWITCH_ALLOW_HASH_TX_TOKEN; + switches[2].tuneId = TUNE_TAP_CASUAL; + switches[2].initState = (HAS_SETTING(S_SIGN_BY_HASH)) ? ON_STATE : OFF_STATE; + + nbgl_useCaseHomeAndSettings(APPNAME, + &C_app_tron_64px, + NULL, + INIT_HOME_PAGE, + &settingContents, + &infoList, + NULL, + onQuitCallback); } #endif // HAVE_NBGL diff --git a/src/ui/ui_review_menu_nbgl.c b/src/ui/ui_review_menu_nbgl.c index e6bf519f..c8aa62fd 100644 --- a/src/ui/ui_review_menu_nbgl.c +++ b/src/ui/ui_review_menu_nbgl.c @@ -92,7 +92,7 @@ static void customContractWarningChoice(bool accept) { } static void displayDataWarning(void) { - nbgl_useCaseChoice(&C_round_warning_64px, + nbgl_useCaseChoice(&C_Important_Circle_64px, "WARNING\nThis transaction\ncontains\nextra data", "Reject if you're not sure", "Continue", @@ -101,7 +101,7 @@ static void displayDataWarning(void) { } static void displayCustomContractWarning(void) { - nbgl_useCaseChoice(&C_round_warning_64px, + nbgl_useCaseChoice(&C_Important_Circle_64px, "WARNING\nCustom Contract\nProceed with care", "Reject if you're not sure", "Continue", @@ -120,7 +120,7 @@ static void reviewStart() { } else if (txInfos.warnings[CUSTOM_CONTRACT_WARNING] == true) { displayFunction = displayCustomContractWarning; } - nbgl_useCaseReviewStart(&C_stax_app_tron_64px, + nbgl_useCaseReviewStart(&C_app_tron_64px, txInfos.flowTitle, txInfos.flowSubtitle, "Reject transaction", @@ -173,7 +173,7 @@ static void prepareTxInfos(ui_approval_state_t state, bool data_warning) { infoLongPress.text = "Sign transaction"; infoLongPress.longPressText = "Hold to sign"; - infoLongPress.icon = &C_stax_app_tron_64px; + infoLongPress.icon = &C_app_tron_64px; pairList.pairs = (nbgl_layoutTagValue_t *) txInfos.fields; @@ -397,33 +397,24 @@ static void prepareTxInfos(ui_approval_state_t state, bool data_warning) { } } -static void address_verification_cancelled(void) { - ui_callback_tx_cancel(false); - nbgl_useCaseStatus("Address verification\ncancelled", false, ui_idle); -} - static void display_address_callback(bool confirm) { if (confirm) { ui_callback_address_ok(false); - nbgl_useCaseStatus("ADDRESS\nVERIFIED", true, ui_idle); + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_idle); } else { - address_verification_cancelled(); + ui_callback_tx_cancel(false); + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_idle); } } -// called when tapping on review start page to actually display address -static void display_addr(void) { - nbgl_useCaseAddressConfirmation(toAddress, &display_address_callback); -} - void ux_flow_display(ui_approval_state_t state, bool data_warning) { if (state == APPROVAL_VERIFY_ADDRESS) { - nbgl_useCaseReviewStart(&C_stax_app_tron_64px, - "Verify Tron\naddress", - NULL, - "Cancel", - display_addr, - address_verification_cancelled); + nbgl_useCaseAddressReview(toAddress, + NULL, + &C_app_tron_64px, + "Verify Tron\naddress", + NULL, + display_address_callback); } else { // Prepare transaction infos to be displayed (field values etc.) prepareTxInfos(state, data_warning); diff --git a/tests/conftest.py b/tests/conftest.py index 78548ae6..e6741674 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,11 +16,24 @@ @pytest.fixture(scope="class") def configuration(backend: BackendInterface, navigator, firmware): if type(backend) is SpeculosBackend: - if firmware.device == "stax": + if firmware.device == "flex": instructions = [ # Go to settings menu. NavIns(NavInsID.USE_CASE_HOME_SETTINGS), + # Allow data in TXs + NavIns(NavInsID.TOUCH, (200, 150)), + # Allow custom contracts + NavIns(NavInsID.TOUCH, (200, 300)), NavIns(NavInsID.USE_CASE_SETTINGS_NEXT), + # Allow sign by hash + NavIns(NavInsID.TOUCH, (200, 150)), + # Go back to main menu. + NavIns(NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT), + ] + elif firmware.device == "stax": + instructions = [ + # Go to settings menu. + NavIns(NavInsID.USE_CASE_HOME_SETTINGS), # Allow data in TXs NavIns(NavInsID.TOUCH, (200, 150)), # Allow custom contracts diff --git a/tests/requirements.txt b/tests/requirements.txt index 825c8b17..4a7d8565 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,9 +1,6 @@ pytest -grpcio==1.44.0 -grpcio-tools==1.44.0 base58==1.0.3 crypto==1.4.1 -cryptography==2.8 eth-keys==0.3.1 ledgerblue==0.1.45 ragger[speculos]>=1.7.1 diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png new file mode 100644 index 00000000..dbabe0d0 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png new file mode 100644 index 00000000..8513846b Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png new file mode 100644 index 00000000..e30874f8 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png new file mode 100644 index 00000000..8513846b Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00004.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00004.png new file mode 100644 index 00000000..4321e601 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00004.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00005.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00005.png new file mode 100644 index 00000000..8a75d8c4 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00005.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png new file mode 100644 index 00000000..dbabe0d0 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png new file mode 100644 index 00000000..45c08d4e Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png new file mode 100644 index 00000000..8a75d8c4 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png new file mode 100644 index 00000000..dbabe0d0 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png new file mode 100644 index 00000000..8513846b Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png new file mode 100644 index 00000000..45c08d4e Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png new file mode 100644 index 00000000..8a75d8c4 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png index 4b27fbfb..a794a345 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png index 9d5a8d2b..75367ff3 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png index 9d5a8d2b..75367ff3 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00004.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00004.png index 13499fcc..3f906b2b 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00004.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00004.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png index 4b27fbfb..a794a345 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png and b/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png index 4b27fbfb..a794a345 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png and b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png index 9d5a8d2b..75367ff3 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png and b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png differ diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py index e67f87a6..7ba36e3a 100644 --- a/tests/test_pubkey_cmd.py +++ b/tests/test_pubkey_cmd.py @@ -47,8 +47,11 @@ def test_get_public_key_confirm_accepted(self, firmware, backend, ROOT_SCREENSHOT_PATH, test_name) else: instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavIns(NavInsID.TOUCH, (200, 335)), + NavInsID.SWIPE_CENTER_TO_LEFT, + NavIns( + NavInsID.TOUCH, + (100 if firmware.device.startswith("flex") else 200, + 400 if firmware.device.startswith("flex") else 335)), NavInsID.USE_CASE_ADDRESS_CONFIRMATION_EXIT_QR, NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM, NavInsID.USE_CASE_STATUS_DISMISS @@ -99,7 +102,7 @@ def test_get_public_key_confirm_refused(self, firmware, backend, navigator, NavInsID.USE_CASE_STATUS_DISMISS ], [ - NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.SWIPE_CENTER_TO_LEFT, NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL, NavInsID.USE_CASE_STATUS_DISMISS ] diff --git a/tests/test_trx.py b/tests/test_trx.py index a2556f8c..608d4e88 100644 --- a/tests/test_trx.py +++ b/tests/test_trx.py @@ -466,7 +466,7 @@ def test_trx_sign_message(self, backend, firmware, navigator): with backend.exchange_async(CLA, InsType.SIGN_PERSONAL_MESSAGE, 0x00, 0x00, data): - if firmware.device == "stax": + if firmware.device == "stax" or firmware.device == "flex": text = "Hold to sign" else: text = "message" @@ -491,7 +491,7 @@ def test_trx_sign_hash(self, backend, firmware, navigator): with backend.exchange_async(CLA, InsType.SIGN_TXN_HASH, 0x00, 0x00, data): - if firmware.device == "stax": + if firmware.device == "stax" or firmware.device == "flex": text = "Hold to sign" else: text = "Sign" @@ -527,7 +527,7 @@ def test_trx_ecdh_key(self, backend, firmware, navigator): data += bytearray.fromhex(f"04{client.getAccount(1)['publicKey'][2:]}") with backend.exchange_async(CLA, InsType.GET_ECDH_SECRET, 0x00, 0x01, data): - if firmware.device == "stax": + if firmware.device == "stax" or firmware.device == "flex": text = "Hold to sign" else: text = "Accept" diff --git a/tests/tron.py b/tests/tron.py index a86c3b40..869dfbf5 100644 --- a/tests/tron.py +++ b/tests/tron.py @@ -198,7 +198,7 @@ def get_next_length(self, tx): return size + newpos def navigate(self, snappath: Path = None, text: str = ""): - if self._firmware.device == "stax": + if self._firmware.device == "stax" or self._firmware.device == "flex": self._navigator.navigate_until_text_and_compare( # Use custom touch coordinates to account for warning approve # button position.