Merge pull request #584 from LedgerHQ/cev/B2CA-1558_eip191-streaming
NBGL porting: improve EIP191
@@ -10,6 +10,7 @@ import struct
|
||||
from client import keychain
|
||||
from client.client import EthAppClient, EIP712FieldType
|
||||
|
||||
from ragger.firmware import Firmware
|
||||
|
||||
# global variables
|
||||
app_client: EthAppClient = None
|
||||
@@ -391,7 +392,7 @@ def next_timeout(_signum: int, _frame):
|
||||
|
||||
|
||||
def enable_autonext():
|
||||
if app_client._client.firmware.device in ("stax", "flex"):
|
||||
if app_client._client.firmware in (Firmware.STAX, Firmware.FLEX):
|
||||
delay = 1/3
|
||||
else:
|
||||
delay = 1/4
|
||||
|
||||
@@ -11,31 +11,29 @@ class SettingID(Enum):
|
||||
DEBUG_DATA = auto()
|
||||
|
||||
|
||||
def get_device_settings(device: str) -> list[SettingID]:
|
||||
if device == "nanos":
|
||||
def get_device_settings(firmware: Firmware) -> list[SettingID]:
|
||||
if firmware == Firmware.NANOS:
|
||||
return [
|
||||
SettingID.NONCE,
|
||||
SettingID.DEBUG_DATA,
|
||||
]
|
||||
if device in ("nanox", "nanosp", "stax", "flex"):
|
||||
return [
|
||||
SettingID.VERBOSE_ENS,
|
||||
SettingID.VERBOSE_EIP712,
|
||||
SettingID.NONCE,
|
||||
SettingID.DEBUG_DATA,
|
||||
]
|
||||
return []
|
||||
return [
|
||||
SettingID.VERBOSE_ENS,
|
||||
SettingID.VERBOSE_EIP712,
|
||||
SettingID.NONCE,
|
||||
SettingID.DEBUG_DATA,
|
||||
]
|
||||
|
||||
|
||||
def get_setting_per_page(device: str) -> int:
|
||||
if device == "stax":
|
||||
def get_setting_per_page(firmware: Firmware) -> int:
|
||||
if firmware == Firmware.STAX:
|
||||
return 3
|
||||
return 2
|
||||
|
||||
|
||||
def get_setting_position(device: str, setting: Union[NavInsID, SettingID]) -> tuple[int, int]:
|
||||
settings_per_page = get_setting_per_page(device)
|
||||
if device == "stax":
|
||||
def get_setting_position(firmware: Firmware, setting: Union[NavInsID, SettingID]) -> tuple[int, int]:
|
||||
settings_per_page = get_setting_per_page(firmware)
|
||||
if firmware == Firmware.STAX:
|
||||
screen_height = 672 # px
|
||||
header_height = 88 # px
|
||||
footer_height = 92 # px
|
||||
@@ -47,15 +45,15 @@ def get_setting_position(device: str, setting: Union[NavInsID, SettingID]) -> tu
|
||||
option_offset = 420 # px
|
||||
usable_height = screen_height - (header_height + footer_height)
|
||||
setting_height = usable_height // settings_per_page
|
||||
index_in_page = get_device_settings(device).index(SettingID(setting)) % settings_per_page
|
||||
index_in_page = get_device_settings(firmware).index(SettingID(setting)) % settings_per_page
|
||||
return option_offset, header_height + (setting_height * index_in_page) + (setting_height // 2)
|
||||
|
||||
|
||||
def settings_toggle(fw: Firmware, nav: Navigator, to_toggle: list[SettingID]):
|
||||
def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingID]):
|
||||
moves: list[Union[NavIns, NavInsID]] = list()
|
||||
settings = get_device_settings(fw.device)
|
||||
settings = get_device_settings(firmware)
|
||||
# Assume the app is on the home page
|
||||
if fw.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 2
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
for setting in settings:
|
||||
@@ -65,12 +63,12 @@ def settings_toggle(fw: Firmware, nav: Navigator, to_toggle: list[SettingID]):
|
||||
moves += [NavInsID.BOTH_CLICK] # Back
|
||||
else:
|
||||
moves += [NavInsID.USE_CASE_HOME_SETTINGS]
|
||||
settings_per_page = get_setting_per_page(fw.device)
|
||||
settings_per_page = get_setting_per_page(firmware)
|
||||
for setting in settings:
|
||||
setting_idx = settings.index(setting)
|
||||
if (setting_idx > 0) and (setting_idx % settings_per_page) == 0:
|
||||
moves += [NavInsID.USE_CASE_SETTINGS_NEXT]
|
||||
if setting in to_toggle:
|
||||
moves += [NavIns(NavInsID.TOUCH, get_setting_position(fw.device, setting))]
|
||||
moves += [NavIns(NavInsID.TOUCH, get_setting_position(firmware, setting))]
|
||||
moves += [NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT]
|
||||
nav.navigate(moves, screen_change_before_first_instruction=False)
|
||||
|
||||
@@ -4,9 +4,10 @@ sdk = "C"
|
||||
devices = ["nanos", "nanox", "nanos+", "stax", "flex"]
|
||||
|
||||
[use_cases] # Coherent build options that make sense for your application
|
||||
debug = "DEBUG=1"
|
||||
use_test_keys = "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
|
||||
cal_bypass = "DEBUG=1 BYPASS_SIGNATURES=1"
|
||||
test_keys = "CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
|
||||
dbg_test_keys = "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
|
||||
cal_bypass = "BYPASS_SIGNATURES=1"
|
||||
dbg_cal_bypass = "DEBUG=1 BYPASS_SIGNATURES=1"
|
||||
|
||||
[tests]
|
||||
unit_directory = "./tests/unit"
|
||||
|
||||
@@ -51,7 +51,7 @@ static void reviewChoice(bool confirm) {
|
||||
}
|
||||
}
|
||||
|
||||
static const nbgl_icon_details_t *get_tx_icon(void) {
|
||||
const nbgl_icon_details_t *get_tx_icon(void) {
|
||||
const nbgl_icon_details_t *icon = NULL;
|
||||
|
||||
if (tx_approval_context.fromPlugin && (pluginType == EXTERNAL)) {
|
||||
|
||||
@@ -4,30 +4,25 @@
|
||||
#include "network.h"
|
||||
|
||||
typedef enum { PARAMETER_CONFIRMATION, SELECTOR_CONFIRMATION } e_confirmation_type;
|
||||
static nbgl_contentTagValue_t pair;
|
||||
static nbgl_contentTagValueList_t pairsList;
|
||||
|
||||
enum {
|
||||
TOKEN_APPROVE = FIRST_USER_TOKEN,
|
||||
};
|
||||
|
||||
static void reviewReject(void) {
|
||||
io_seproxyhal_touch_data_cancel(NULL);
|
||||
}
|
||||
|
||||
static void long_press_cb(int token, uint8_t index, int page) {
|
||||
UNUSED(index);
|
||||
UNUSED(page);
|
||||
if (token == TOKEN_APPROVE) {
|
||||
static void reviewChoice(bool confirm) {
|
||||
if (confirm) {
|
||||
io_seproxyhal_touch_data_ok(NULL);
|
||||
} else {
|
||||
io_seproxyhal_touch_data_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void buildScreen(e_confirmation_type confirm_type) {
|
||||
static nbgl_genericContents_t contents = {0};
|
||||
static nbgl_content_t contentsList[3] = {0};
|
||||
static nbgl_contentTagValue_t pair = {0};
|
||||
uint8_t nbContents = 0;
|
||||
uint32_t buf_size = SHARED_BUFFER_SIZE / 2;
|
||||
nbgl_operationType_t op = TYPE_TRANSACTION;
|
||||
|
||||
pair.item = (confirm_type == PARAMETER_CONFIRMATION) ? "Parameter" : "Selector";
|
||||
pair.value = strings.tmp.tmp;
|
||||
pairsList.nbPairs = 1;
|
||||
pairsList.pairs = &pair;
|
||||
snprintf(g_stax_shared_buffer,
|
||||
buf_size,
|
||||
"Verify %s",
|
||||
@@ -38,37 +33,16 @@ static void buildScreen(e_confirmation_type confirm_type) {
|
||||
"Confirm %s",
|
||||
(confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector");
|
||||
|
||||
pair.item = (confirm_type == PARAMETER_CONFIRMATION) ? "Parameter" : "Selector";
|
||||
pair.value = strings.tmp.tmp;
|
||||
|
||||
// Title page
|
||||
contentsList[nbContents].type = CENTERED_INFO;
|
||||
contentsList[nbContents].content.centeredInfo.text1 = g_stax_shared_buffer;
|
||||
contentsList[nbContents].content.centeredInfo.icon = get_app_icon(true);
|
||||
contentsList[nbContents].content.centeredInfo.style = LARGE_CASE_INFO;
|
||||
nbContents++;
|
||||
|
||||
// Values to be reviewed
|
||||
contentsList[nbContents].type = TAG_VALUE_LIST;
|
||||
contentsList[nbContents].content.tagValueList.pairs = &pair;
|
||||
contentsList[nbContents].content.tagValueList.nbPairs = 1;
|
||||
nbContents++;
|
||||
|
||||
// Approval screen
|
||||
contentsList[nbContents].type = INFO_LONG_PRESS;
|
||||
contentsList[nbContents].content.infoLongPress.text = g_stax_shared_buffer + buf_size;
|
||||
contentsList[nbContents].content.infoLongPress.icon = get_app_icon(true);
|
||||
contentsList[nbContents].content.infoLongPress.longPressText = "Hold to confirm";
|
||||
contentsList[nbContents].content.infoLongPress.longPressToken = TOKEN_APPROVE;
|
||||
contentsList[nbContents].content.infoLongPress.tuneId = NB_TUNES;
|
||||
contentsList[nbContents].contentActionCallback = long_press_cb;
|
||||
nbContents++;
|
||||
|
||||
contents.callbackCallNeeded = false;
|
||||
contents.contentsList = contentsList;
|
||||
contents.nbContents = nbContents;
|
||||
|
||||
nbgl_useCaseGenericReview(&contents, REJECT_BUTTON, reviewReject);
|
||||
if (tmpContent.txContent.dataPresent) {
|
||||
op |= BLIND_OPERATION;
|
||||
}
|
||||
nbgl_useCaseReview(op,
|
||||
&pairsList,
|
||||
get_tx_icon(),
|
||||
g_stax_shared_buffer,
|
||||
NULL,
|
||||
g_stax_shared_buffer + buf_size,
|
||||
reviewChoice);
|
||||
}
|
||||
|
||||
void ui_confirm_parameter(void) {
|
||||
|
||||
@@ -4,64 +4,32 @@
|
||||
#include "nbgl_use_case.h"
|
||||
#include "nbgl_content.h"
|
||||
|
||||
enum {
|
||||
TOKEN_APPROVE = FIRST_USER_TOKEN,
|
||||
};
|
||||
|
||||
static void reviewReject(void) {
|
||||
io_seproxyhal_touch_privacy_cancel(NULL);
|
||||
}
|
||||
|
||||
static void long_press_cb(int token, uint8_t index, int page) {
|
||||
UNUSED(index);
|
||||
UNUSED(page);
|
||||
if (token == TOKEN_APPROVE) {
|
||||
static void reviewChoice(bool confirm) {
|
||||
if (confirm) {
|
||||
io_seproxyhal_touch_privacy_ok(NULL);
|
||||
} else {
|
||||
io_seproxyhal_touch_privacy_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void buildFirstPage(const char *review_string) {
|
||||
static nbgl_genericContents_t contents = {0};
|
||||
static nbgl_content_t contentsList[3] = {0};
|
||||
static nbgl_contentTagValue_t pairs[2] = {0};
|
||||
uint8_t nbContents = 0;
|
||||
uint8_t nbPairs = 0;
|
||||
static nbgl_contentTagValueList_t pairsList = {0};
|
||||
|
||||
pairs[nbPairs].item = "Address";
|
||||
pairs[nbPairs].value = strings.common.toAddress;
|
||||
nbPairs++;
|
||||
pairs[nbPairs].item = "Key";
|
||||
pairs[nbPairs].value = strings.common.fullAmount;
|
||||
nbPairs++;
|
||||
pairs[0].item = "Address";
|
||||
pairs[0].value = strings.common.toAddress;
|
||||
pairs[1].item = "Key";
|
||||
pairs[1].value = strings.common.fullAmount;
|
||||
pairsList.nbPairs = 2;
|
||||
pairsList.pairs = pairs;
|
||||
|
||||
// Title page
|
||||
contentsList[nbContents].type = CENTERED_INFO;
|
||||
contentsList[nbContents].content.centeredInfo.text1 = review_string;
|
||||
contentsList[nbContents].content.centeredInfo.icon = get_app_icon(true);
|
||||
contentsList[nbContents].content.centeredInfo.style = LARGE_CASE_INFO;
|
||||
nbContents++;
|
||||
|
||||
// Values to be reviewed
|
||||
contentsList[nbContents].type = TAG_VALUE_LIST;
|
||||
contentsList[nbContents].content.tagValueList.pairs = pairs;
|
||||
contentsList[nbContents].content.tagValueList.nbPairs = nbPairs;
|
||||
nbContents++;
|
||||
|
||||
// Approval screen
|
||||
contentsList[nbContents].type = INFO_LONG_PRESS;
|
||||
contentsList[nbContents].content.infoLongPress.text = review_string;
|
||||
contentsList[nbContents].content.infoLongPress.icon = get_app_icon(true);
|
||||
contentsList[nbContents].content.infoLongPress.longPressText = "Hold to approve";
|
||||
contentsList[nbContents].content.infoLongPress.longPressToken = TOKEN_APPROVE;
|
||||
contentsList[nbContents].content.infoLongPress.tuneId = NB_TUNES;
|
||||
contentsList[nbContents].contentActionCallback = long_press_cb;
|
||||
nbContents++;
|
||||
|
||||
contents.callbackCallNeeded = false;
|
||||
contents.contentsList = contentsList;
|
||||
contents.nbContents = nbContents;
|
||||
|
||||
nbgl_useCaseGenericReview(&contents, REJECT_BUTTON, reviewReject);
|
||||
nbgl_useCaseReview(TYPE_OPERATION,
|
||||
&pairsList,
|
||||
get_tx_icon(),
|
||||
review_string,
|
||||
NULL,
|
||||
review_string,
|
||||
reviewChoice);
|
||||
}
|
||||
|
||||
void ui_display_privacy_public_key(void) {
|
||||
|
||||
@@ -1,45 +1,5 @@
|
||||
#include "ui_nbgl.h"
|
||||
#include "ui_signing.h"
|
||||
#include "ui_logic.h"
|
||||
#include "ui_message_signing.h"
|
||||
#include "glyphs.h"
|
||||
|
||||
static void (*g_approved_func)(void) = NULL;
|
||||
static void (*g_rejected_func)(void) = NULL;
|
||||
|
||||
static void ui_message_rejection_handler() {
|
||||
nbgl_useCaseStatus("Message signing\ncancelled", false, g_rejected_func);
|
||||
}
|
||||
|
||||
static void ui_message_confirm_rejection(void) {
|
||||
nbgl_useCaseConfirm(REJECT_QUESTION(TEXT_MESSAGE),
|
||||
NULL,
|
||||
REJECT_CONFIRM_BUTTON,
|
||||
RESUME(TEXT_MESSAGE),
|
||||
ui_message_rejection_handler);
|
||||
}
|
||||
|
||||
void ui_message_review_choice(bool confirm) {
|
||||
if (confirm) {
|
||||
nbgl_useCaseStatus("MESSAGE\nSIGNED", true, g_approved_func);
|
||||
} else {
|
||||
ui_message_confirm_rejection();
|
||||
}
|
||||
}
|
||||
|
||||
void ui_message_start(const char *title,
|
||||
void (*start_func)(void),
|
||||
void (*approved_func)(void),
|
||||
void (*rejected_func)(void)) {
|
||||
g_approved_func = approved_func;
|
||||
g_rejected_func = rejected_func;
|
||||
nbgl_useCaseReviewStart(&C_Review_64px,
|
||||
title,
|
||||
NULL,
|
||||
REJECT_BUTTON,
|
||||
start_func,
|
||||
ui_message_confirm_rejection);
|
||||
}
|
||||
|
||||
static void ui_message_712_approved(void) {
|
||||
ui_712_approve();
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
#define TEXT_REVIEW_EIP712 REVIEW(TEXT_TYPED_MESSAGE)
|
||||
#define TEXT_SIGN_EIP712 SIGN(TEXT_TYPED_MESSAGE)
|
||||
|
||||
void ui_message_review_choice(bool confirm);
|
||||
void ui_message_start(const char *title,
|
||||
void (*start_func)(void),
|
||||
void (*approved_func)(void),
|
||||
void (*rejected_func)(void));
|
||||
void ui_typed_message_review_choice(bool confirm);
|
||||
|
||||
#endif // UI_MESSAGE_SIGNING_H_
|
||||
|
||||
@@ -11,6 +11,7 @@ extern char g_stax_shared_buffer[SHARED_BUFFER_SIZE];
|
||||
extern nbgl_page_t* pageContext;
|
||||
|
||||
const nbgl_icon_details_t* get_app_icon(bool caller_icon);
|
||||
const nbgl_icon_details_t* get_tx_icon(void);
|
||||
|
||||
void ui_idle(void);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <nbgl_page.h>
|
||||
#include "nbgl_page.h"
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "ui_nbgl.h"
|
||||
@@ -20,12 +20,14 @@ typedef enum {
|
||||
|
||||
static e_ui_191_action g_action;
|
||||
|
||||
static bool skip_message;
|
||||
|
||||
static nbgl_contentTagValue_t pair;
|
||||
static nbgl_contentTagValueList_t pairs_list;
|
||||
|
||||
static uint32_t eip191MessageIdx = 0;
|
||||
static uint32_t stringsTmpTmpIdx = 0;
|
||||
static uint32_t g_display_buffer_idx;
|
||||
static uint32_t g_rcv_buffer_idx;
|
||||
static bool g_skipped;
|
||||
|
||||
static void ui_191_process_state(void);
|
||||
|
||||
static void reject_message(void) {
|
||||
io_seproxyhal_touch_signMessage_cancel();
|
||||
@@ -35,125 +37,111 @@ static void sign_message(void) {
|
||||
io_seproxyhal_touch_signMessage_ok();
|
||||
}
|
||||
|
||||
static bool display_message(nbgl_pageContent_t *content) {
|
||||
static void ui_191_finish_cb(bool confirm) {
|
||||
if (confirm) {
|
||||
nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, sign_message);
|
||||
} else {
|
||||
nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, reject_message);
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_191_skip_cb(void) {
|
||||
g_skipped = true;
|
||||
skip_rest_of_message();
|
||||
}
|
||||
|
||||
static bool ui_191_update_display_buffer(void) {
|
||||
uint16_t len = 0;
|
||||
bool reached;
|
||||
|
||||
if (g_action == UI_191_ACTION_ADVANCE_IN_MESSAGE) {
|
||||
strncpy(g_stax_shared_buffer + eip191MessageIdx,
|
||||
strings.tmp.tmp + stringsTmpTmpIdx,
|
||||
SHARED_BUFFER_SIZE - eip191MessageIdx);
|
||||
reached = nbgl_getTextMaxLenInNbLines(LARGE_MEDIUM_FONT,
|
||||
(char *) g_stax_shared_buffer,
|
||||
SCREEN_WIDTH - (2 * BORDER_MARGIN),
|
||||
NB_MAX_LINES_IN_REVIEW,
|
||||
#if (API_LEVEL == 0 || API_LEVEL >= 14)
|
||||
&len,
|
||||
false);
|
||||
#else
|
||||
&len);
|
||||
#endif
|
||||
g_stax_shared_buffer[g_display_buffer_idx] = '\0';
|
||||
strlcat(g_stax_shared_buffer + g_display_buffer_idx,
|
||||
strings.tmp.tmp + g_rcv_buffer_idx,
|
||||
sizeof(g_stax_shared_buffer) - g_display_buffer_idx);
|
||||
reached = nbgl_getTextMaxLenInNbLines(LARGE_MEDIUM_FONT,
|
||||
(char *) g_stax_shared_buffer,
|
||||
SCREEN_WIDTH - (2 * BORDER_MARGIN),
|
||||
NB_MAX_LINES_IN_REVIEW,
|
||||
&len,
|
||||
false);
|
||||
|
||||
stringsTmpTmpIdx = len - eip191MessageIdx;
|
||||
eip191MessageIdx = len;
|
||||
g_stax_shared_buffer[eip191MessageIdx] = '\0';
|
||||
g_rcv_buffer_idx += (len - g_display_buffer_idx);
|
||||
g_display_buffer_idx = len;
|
||||
g_stax_shared_buffer[g_display_buffer_idx] = '\0';
|
||||
|
||||
if (!reached && eip191MessageIdx < SHARED_BUFFER_SIZE) {
|
||||
stringsTmpTmpIdx = 0;
|
||||
question_switcher();
|
||||
|
||||
if (g_action != UI_191_ACTION_GO_TO_SIGN) {
|
||||
return false;
|
||||
}
|
||||
} else if (reached || eip191MessageIdx == SHARED_BUFFER_SIZE) {
|
||||
eip191MessageIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pair.value = g_stax_shared_buffer;
|
||||
pair.item = "Message";
|
||||
content->type = TAG_VALUE_LIST;
|
||||
content->tagValueList.nbPairs = 1;
|
||||
content->tagValueList.pairs = &pair;
|
||||
content->tagValueList.smallCaseForValue = false;
|
||||
content->tagValueList.nbMaxLinesForValue = NB_MAX_LINES_IN_REVIEW;
|
||||
content->tagValueList.wrapping = false;
|
||||
|
||||
if ((g_action != UI_191_ACTION_IDLE) && (stringsTmpTmpIdx >= strlen(strings.tmp.tmp))) {
|
||||
// Fetch the next content to display into strings.tmp.tmp buffer.
|
||||
stringsTmpTmpIdx = 0;
|
||||
if (!reached) {
|
||||
g_rcv_buffer_idx = 0;
|
||||
question_switcher();
|
||||
return false;
|
||||
}
|
||||
g_display_buffer_idx = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool display_sign(nbgl_pageContent_t *content) {
|
||||
bool ret = false;
|
||||
|
||||
if (g_position != UI_SIGNING_POSITION_SIGN) {
|
||||
content->type = INFO_LONG_PRESS, content->infoLongPress.icon = &C_Review_64px;
|
||||
content->infoLongPress.text = TEXT_SIGN_EIP191;
|
||||
content->infoLongPress.longPressText = SIGN_BUTTON;
|
||||
g_position = UI_SIGNING_POSITION_SIGN;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) {
|
||||
bool ret = true;
|
||||
|
||||
if (page == LAST_PAGE_FOR_REVIEW) { // was skipped
|
||||
skip_message = true;
|
||||
skip_rest_of_message();
|
||||
}
|
||||
if ((g_action != UI_191_ACTION_GO_TO_SIGN) && (g_position != UI_SIGNING_POSITION_SIGN)) {
|
||||
if (skip_message) {
|
||||
// do not refresh when this callback triggers after user validation
|
||||
ret = false;
|
||||
} else {
|
||||
ret = display_message(content);
|
||||
}
|
||||
static void ui_191_data_cb(bool more) {
|
||||
if (more) {
|
||||
ui_191_process_state();
|
||||
} else {
|
||||
// the last page must contain a long press button
|
||||
ret = display_sign(content);
|
||||
ui_191_finish_cb(false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void continue_review(void) {
|
||||
nbgl_useCaseForwardOnlyReview(REJECT_BUTTON, NULL, nav_callback, ui_message_review_choice);
|
||||
static void ui_191_show_message(void) {
|
||||
pair.value = g_stax_shared_buffer;
|
||||
pair.item = "Message";
|
||||
pairs_list.nbPairs = 1;
|
||||
pairs_list.pairs = &pair;
|
||||
pairs_list.smallCaseForValue = false;
|
||||
pairs_list.nbMaxLinesForValue = NB_MAX_LINES_IN_REVIEW;
|
||||
pairs_list.wrapping = false;
|
||||
nbgl_useCaseReviewStreamingContinueExt(&pairs_list, ui_191_data_cb, ui_191_skip_cb);
|
||||
}
|
||||
|
||||
static void ui_191_process_state(void) {
|
||||
switch (g_action) {
|
||||
case UI_191_ACTION_IDLE:
|
||||
g_action = UI_191_ACTION_ADVANCE_IN_MESSAGE;
|
||||
__attribute__((fallthrough));
|
||||
case UI_191_ACTION_ADVANCE_IN_MESSAGE:
|
||||
if (ui_191_update_display_buffer()) {
|
||||
ui_191_show_message();
|
||||
}
|
||||
break;
|
||||
case UI_191_ACTION_GO_TO_SIGN:
|
||||
nbgl_useCaseReviewStreamingFinish(TEXT_SIGN_EIP191, ui_191_finish_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_191_start(void) {
|
||||
g_position = UI_SIGNING_POSITION_START;
|
||||
g_action = UI_191_ACTION_IDLE;
|
||||
g_display_buffer_idx = 0;
|
||||
g_rcv_buffer_idx = 0;
|
||||
g_skipped = false;
|
||||
|
||||
skip_message = false;
|
||||
eip191MessageIdx = 0;
|
||||
stringsTmpTmpIdx = 0;
|
||||
|
||||
ui_message_start(TEXT_REVIEW_EIP191, &ui_191_switch_to_message, &sign_message, &reject_message);
|
||||
nbgl_useCaseReviewStreamingStart(TYPE_MESSAGE | SKIPPABLE_OPERATION,
|
||||
&C_Review_64px,
|
||||
TEXT_REVIEW_EIP191,
|
||||
NULL,
|
||||
ui_191_data_cb);
|
||||
}
|
||||
|
||||
void ui_191_switch_to_message(void) {
|
||||
g_position = UI_SIGNING_POSITION_REVIEW;
|
||||
g_action = UI_191_ACTION_ADVANCE_IN_MESSAGE;
|
||||
// No question mechanism on Stax:
|
||||
// Message is already displayed
|
||||
continue_review();
|
||||
// Get following part of the message
|
||||
ui_191_process_state();
|
||||
}
|
||||
|
||||
void ui_191_switch_to_sign(void) {
|
||||
g_action = UI_191_ACTION_GO_TO_SIGN;
|
||||
// Next nav_callback callback must display
|
||||
// the hold to approve screen
|
||||
if (skip_message) {
|
||||
continue_review(); // to force screen refresh
|
||||
if (g_skipped) {
|
||||
nbgl_useCaseReviewStreamingFinish(TEXT_SIGN_EIP191, ui_191_finish_cb);
|
||||
} else if (g_display_buffer_idx > 0) {
|
||||
// still on an incomplete display buffer, show it before the last page
|
||||
ui_191_show_message();
|
||||
}
|
||||
}
|
||||
|
||||
void ui_191_switch_to_question(void) {
|
||||
// No question mechanism on Stax:
|
||||
// Always display the next message chunk.
|
||||
// No question mechanism on Stax: Always display the next message chunk.
|
||||
continue_displaying_message();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from os import path
|
||||
import warnings
|
||||
import glob
|
||||
|
||||
@@ -17,8 +18,8 @@ def pytest_addoption(parser):
|
||||
parser.addoption("--with_lib_mode", action="store_true", help="Run the test with Library Mode")
|
||||
|
||||
|
||||
parent: Path = Path(__file__).parent
|
||||
testFiles = glob.glob("test_*.py", root_dir=f"{parent}")
|
||||
pattern = f"{Path(__file__).parent}/test_*.py"
|
||||
testFiles = [path.basename(x) for x in glob.glob(pattern)]
|
||||
collect_ignore = []
|
||||
if "--with_lib_mode" in sys.argv:
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ disable = C0114, # missing-module-docstring
|
||||
C0103, # invalid-name
|
||||
R0801, # duplicate-code
|
||||
R0903, # too-few-public-methods
|
||||
R0904, # too-many-public-methods
|
||||
R0911, # too-many-statements
|
||||
R0912, # too-many-branches
|
||||
R0913, # too-many-arguments
|
||||
R0914, # too-many-locals
|
||||
W0603, # global-statement
|
||||
|
||||
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -7,7 +7,6 @@ from web3 import Web3
|
||||
from ragger.backend import BackendInterface
|
||||
from ragger.firmware import Firmware
|
||||
from ragger.navigator import Navigator, NavInsID
|
||||
from ragger.navigator.navigation_scenario import NavigateWithScenario
|
||||
from ragger.error import ExceptionRAPDU
|
||||
|
||||
from constants import ABIS_FOLDER
|
||||
@@ -77,8 +76,8 @@ def test_blind_sign(firmware: Firmware,
|
||||
test_name += "_rejected"
|
||||
|
||||
moves = []
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.device == "nanos":
|
||||
if firmware.is_nano:
|
||||
if firmware == Firmware.NANOS:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 2
|
||||
else:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 4
|
||||
@@ -89,13 +88,13 @@ def test_blind_sign(firmware: Firmware,
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
|
||||
if sign:
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 10
|
||||
else:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 6
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
else:
|
||||
if firmware.device == "stax":
|
||||
if firmware == Firmware.STAX:
|
||||
tap_number = 2
|
||||
else:
|
||||
tap_number = 3
|
||||
@@ -126,7 +125,7 @@ def test_blind_sign_reject_in_risk_review(firmware: Firmware,
|
||||
test_name: str):
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
if firmware.device not in ["stax", "flex"]:
|
||||
if firmware.is_nano:
|
||||
pytest.skip("Not supported on non-NBGL apps")
|
||||
|
||||
try:
|
||||
@@ -146,7 +145,6 @@ def test_blind_sign_reject_in_risk_review(firmware: Firmware,
|
||||
def test_sign_parameter_selector(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
navigator: Navigator,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
global DEVICE_ADDR
|
||||
@@ -168,8 +166,8 @@ def test_sign_parameter_selector(firmware: Firmware,
|
||||
flows += data_len // 32
|
||||
with app_client.sign(BIP32_PATH, tx_params):
|
||||
moves = []
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.device == "nanos":
|
||||
if firmware.is_nano:
|
||||
if firmware == Firmware.NANOS:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 2 + [NavInsID.BOTH_CLICK]
|
||||
# Parameters on Nano S are split on multiple pages, hardcoded because the two parameters don't use the
|
||||
# same amount of pages because of non-monospace fonts
|
||||
@@ -178,19 +176,19 @@ def test_sign_parameter_selector(firmware: Firmware,
|
||||
else:
|
||||
moves += ([NavInsID.RIGHT_CLICK] * 2 + [NavInsID.BOTH_CLICK]) * flows
|
||||
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 2
|
||||
else:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 4
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 9
|
||||
else:
|
||||
moves += [NavInsID.RIGHT_CLICK] * 5
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
else:
|
||||
if firmware.device == "stax":
|
||||
if firmware == Firmware.STAX:
|
||||
tap_number = 2
|
||||
else:
|
||||
tap_number = 3
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
from web3 import Web3
|
||||
|
||||
@@ -33,7 +32,7 @@ def verbose_fixture(request) -> bool:
|
||||
|
||||
def common(firmware: Firmware, app_client: EthAppClient) -> int:
|
||||
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
pytest.skip("Not supported on LNS")
|
||||
challenge = app_client.get_challenge()
|
||||
return ResponseParser.challenge(challenge.data)
|
||||
@@ -43,7 +42,6 @@ def test_send_fund(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
navigator: Navigator,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
verbose: bool):
|
||||
app_client = EthAppClient(backend)
|
||||
challenge = common(firmware, app_client)
|
||||
@@ -62,12 +60,12 @@ def test_send_fund(firmware: Firmware,
|
||||
"value": Web3.to_wei(AMOUNT, "ether"),
|
||||
"chainId": CHAIN_ID
|
||||
}):
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
|
||||
scenario_navigator.review_approve(default_screenshot_path, f"domain_name_verbose_{str(verbose)}", end_text)
|
||||
scenario_navigator.review_approve(test_name=f"domain_name_verbose_{str(verbose)}", custom_screen_text=end_text)
|
||||
|
||||
|
||||
def test_send_fund_wrong_challenge(firmware: Firmware, backend: BackendInterface):
|
||||
@@ -81,8 +79,7 @@ def test_send_fund_wrong_challenge(firmware: Firmware, backend: BackendInterface
|
||||
|
||||
def test_send_fund_wrong_addr(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
app_client = EthAppClient(backend)
|
||||
challenge = common(firmware, app_client)
|
||||
|
||||
@@ -100,18 +97,17 @@ def test_send_fund_wrong_addr(firmware: Firmware,
|
||||
"value": Web3.to_wei(AMOUNT, "ether"),
|
||||
"chainId": CHAIN_ID
|
||||
}):
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
|
||||
scenario_navigator.review_approve(default_screenshot_path, "domain_name_wrong_addr", end_text)
|
||||
scenario_navigator.review_approve(test_name="domain_name_wrong_addr", custom_screen_text=end_text)
|
||||
|
||||
|
||||
def test_send_fund_non_mainnet(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
app_client = EthAppClient(backend)
|
||||
challenge = common(firmware, app_client)
|
||||
|
||||
@@ -126,18 +122,17 @@ def test_send_fund_non_mainnet(firmware: Firmware,
|
||||
"value": Web3.to_wei(AMOUNT, "ether"),
|
||||
"chainId": 5
|
||||
}):
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
|
||||
scenario_navigator.review_approve(default_screenshot_path, "domain_name_non_mainnet", end_text)
|
||||
scenario_navigator.review_approve(test_name="domain_name_non_mainnet", custom_screen_text=end_text)
|
||||
|
||||
|
||||
def test_send_fund_unknown_chain(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
app_client = EthAppClient(backend)
|
||||
challenge = common(firmware, app_client)
|
||||
|
||||
@@ -152,12 +147,12 @@ def test_send_fund_unknown_chain(firmware: Firmware,
|
||||
"value": Web3.to_wei(AMOUNT, "ether"),
|
||||
"chainId": 9
|
||||
}):
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
|
||||
scenario_navigator.review_approve(default_screenshot_path, "domain_name_unknown_chain", end_text)
|
||||
scenario_navigator.review_approve(test_name="domain_name_unknown_chain", custom_screen_text=end_text)
|
||||
|
||||
|
||||
def test_send_fund_domain_too_long(firmware: Firmware, backend: BackendInterface):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from ragger.error import ExceptionRAPDU
|
||||
@@ -17,7 +16,6 @@ BIP32_PATH = "m/44'/60'/0'/0/0"
|
||||
def common(backend: BackendInterface,
|
||||
scenario: NavigateWithScenario,
|
||||
test_name: str,
|
||||
screenshot_path: Path,
|
||||
msg: str):
|
||||
|
||||
app_client = EthAppClient(backend)
|
||||
@@ -27,7 +25,7 @@ def common(backend: BackendInterface,
|
||||
_, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
|
||||
|
||||
with app_client.personal_sign(BIP32_PATH, msg.encode('utf-8')):
|
||||
scenario.review_approve(screenshot_path, test_name, "Sign")
|
||||
scenario.review_approve(test_name=test_name, custom_screen_text="Sign")
|
||||
|
||||
# verify signature
|
||||
vrs = ResponseParser.signature(app_client.response().data)
|
||||
@@ -37,29 +35,26 @@ def common(backend: BackendInterface,
|
||||
|
||||
def test_personal_sign_metamask(backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
test_name: str):
|
||||
|
||||
msg = "Example `personal_sign` message"
|
||||
common(backend, scenario_navigator, test_name, default_screenshot_path, msg)
|
||||
common(backend, scenario_navigator, test_name, msg)
|
||||
|
||||
|
||||
def test_personal_sign_non_ascii(backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
test_name: str):
|
||||
|
||||
msg = "0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658"
|
||||
common(backend, scenario_navigator, test_name, default_screenshot_path, msg)
|
||||
common(backend, scenario_navigator, test_name, msg)
|
||||
|
||||
|
||||
def test_personal_sign_opensea(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
test_name: str):
|
||||
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
pytest.skip("Not supported on LNS")
|
||||
|
||||
msg = "Welcome to OpenSea!\n\n"
|
||||
@@ -67,14 +62,12 @@ def test_personal_sign_opensea(firmware: Firmware,
|
||||
msg += "This request will not trigger a blockchain transaction or cost any gas fees.\n\n"
|
||||
msg += "Your authentication status will reset after 24 hours.\n\n"
|
||||
msg += "Wallet address:\n0x9858effd232b4033e47d90003d41ec34ecaeda94\n\nNonce:\n2b02c8a0-f74f-4554-9821-a28054dc9121"
|
||||
common(backend, scenario_navigator, test_name, default_screenshot_path, msg)
|
||||
common(backend, scenario_navigator, test_name, msg)
|
||||
|
||||
|
||||
def test_personal_sign_reject(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
|
||||
msg = "This is an reject sign"
|
||||
|
||||
@@ -82,11 +75,11 @@ def test_personal_sign_reject(firmware: Firmware,
|
||||
|
||||
try:
|
||||
with app_client.personal_sign(BIP32_PATH, msg.encode('utf-8')):
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Cancel"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
scenario_navigator.review_reject(default_screenshot_path, test_name, end_text)
|
||||
scenario_navigator.review_reject(custom_screen_text=end_text)
|
||||
|
||||
except ExceptionRAPDU as e:
|
||||
assert e.status == StatusWord.CONDITION_NOT_SATISFIED
|
||||
|
||||
@@ -90,7 +90,7 @@ def test_eip712_legacy(backend: BackendInterface, scenario_navigator: NavigateWi
|
||||
|
||||
def autonext(firmware: Firmware, navigator: Navigator, default_screenshot_path: Path):
|
||||
moves = []
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
moves = [NavInsID.RIGHT_CLICK]
|
||||
else:
|
||||
moves = [NavInsID.SWIPE_CENTER_TO_LEFT]
|
||||
@@ -123,10 +123,10 @@ def eip712_new_common(firmware: Firmware,
|
||||
golden_run)
|
||||
with app_client.eip712_sign_new(BIP32_PATH):
|
||||
moves = []
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
# need to skip the message hash
|
||||
if not verbose and filters is None:
|
||||
moves = [NavInsID.RIGHT_CLICK] * 2
|
||||
moves += [NavInsID.RIGHT_CLICK] * 2
|
||||
moves += [NavInsID.BOTH_CLICK]
|
||||
else:
|
||||
# this move is necessary most of the times, but can't be 100% sure with the fields grouping
|
||||
@@ -159,7 +159,7 @@ def test_eip712_new(firmware: Firmware,
|
||||
verbose: bool,
|
||||
filtering: bool):
|
||||
app_client = EthAppClient(backend)
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
pytest.skip("Not supported on LNS")
|
||||
|
||||
test_path = f"{input_file.parent}/{'-'.join(input_file.stem.split('-')[:-1])}"
|
||||
@@ -420,7 +420,7 @@ def test_eip712_advanced_filtering(firmware: Firmware,
|
||||
global SNAPS_CONFIG
|
||||
|
||||
app_client = EthAppClient(backend)
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
pytest.skip("Not supported on LNS")
|
||||
|
||||
SNAPS_CONFIG = SnapshotsConfig(test_name + data_set.suffix)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import pytest
|
||||
|
||||
@@ -36,27 +35,25 @@ def chain_fixture(request) -> Optional[int]:
|
||||
)
|
||||
def test_get_pk_rejected(backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
path,
|
||||
suffix):
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
with pytest.raises(ExceptionRAPDU) as e:
|
||||
with app_client.get_public_addr(bip32_path=path):
|
||||
scenario_navigator.address_review_reject(default_screenshot_path, f"get_pk_rejected_{suffix}")
|
||||
scenario_navigator.address_review_reject(test_name=f"get_pk_rejected_{suffix}")
|
||||
|
||||
assert e.value.status == StatusWord.CONDITION_NOT_SATISFIED
|
||||
|
||||
|
||||
def test_get_pk(backend: BackendInterface,
|
||||
default_screenshot_path: Path,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
with_chaincode: bool,
|
||||
chain: Optional[int]):
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
with app_client.get_public_addr(chaincode=with_chaincode, chain_id=chain):
|
||||
scenario_navigator.address_review_approve(default_screenshot_path, f"get_pk_{chain}")
|
||||
scenario_navigator.address_review_approve(test_name=f"get_pk_{chain}")
|
||||
|
||||
pk, _, chaincode = ResponseParser.pk_addr(app_client.response().data, with_chaincode)
|
||||
ref_pk, ref_chaincode = calculate_public_key_and_chaincode(curve=CurveChoice.Secp256k1,
|
||||
@@ -69,18 +66,17 @@ def test_get_pk(backend: BackendInterface,
|
||||
def test_get_eth2_pk(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
test_name: str):
|
||||
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
path="m/12381/3600/0/0"
|
||||
with app_client.get_eth2_public_addr(bip32_path=path):
|
||||
scenario_navigator.address_review_approve(default_screenshot_path, test_name)
|
||||
scenario_navigator.address_review_approve(test_name=test_name)
|
||||
|
||||
pk = app_client.response().data
|
||||
ref_pk = bls.SkToPk(mnemonic_and_path_to_key(SPECULOS_MNEMONIC, path))
|
||||
if firmware.name in ("stax", "flex"):
|
||||
if firmware in (Firmware.STAX, Firmware.FLEX):
|
||||
pk = pk[1:49]
|
||||
|
||||
assert pk == ref_pk
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional, Any
|
||||
import json
|
||||
import pytest
|
||||
@@ -51,7 +50,6 @@ class Action:
|
||||
def common_test_nft(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
collec: NFTCollection,
|
||||
action: Action,
|
||||
reject: bool,
|
||||
@@ -59,7 +57,7 @@ def common_test_nft(firmware: Firmware,
|
||||
global DEVICE_ADDR
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
if firmware.device == "nanos":
|
||||
if firmware == Firmware.NANOS:
|
||||
pytest.skip("Not supported on LNS")
|
||||
|
||||
if DEVICE_ADDR is None: # to only have to request it once
|
||||
@@ -86,13 +84,13 @@ def common_test_nft(firmware: Firmware,
|
||||
test_name = f"{plugin_name.lower()}_{action.fn_name}_{str(collec.chain_id)}"
|
||||
if reject:
|
||||
test_name += "-rejected"
|
||||
scenario_navigator.review_reject(default_screenshot_path, test_name)
|
||||
scenario_navigator.review_reject(test_name=test_name)
|
||||
else:
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
scenario_navigator.review_approve(default_screenshot_path, test_name, end_text)
|
||||
scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
|
||||
|
||||
# verify signature
|
||||
vrs = ResponseParser.signature(app_client.response().data)
|
||||
@@ -104,11 +102,10 @@ def common_test_nft_reject(test_fn: Callable,
|
||||
firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
collec: NFTCollection,
|
||||
action: Action):
|
||||
with pytest.raises(ExceptionRAPDU) as e:
|
||||
test_fn(firmware, backend, scenario_navigator, default_screenshot_path, collec, action, True)
|
||||
test_fn(firmware, backend, scenario_navigator, collec, action, True)
|
||||
assert e.value.status == StatusWord.CONDITION_NOT_SATISFIED
|
||||
|
||||
# ERC-721
|
||||
@@ -158,14 +155,12 @@ def action_721_fixture(request) -> Action:
|
||||
def test_erc721(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
collec_721: NFTCollection,
|
||||
action_721: Action,
|
||||
reject: bool = False):
|
||||
common_test_nft(firmware,
|
||||
backend,
|
||||
scenario_navigator,
|
||||
default_screenshot_path,
|
||||
collec_721,
|
||||
action_721,
|
||||
reject,
|
||||
@@ -174,13 +169,11 @@ def test_erc721(firmware: Firmware,
|
||||
|
||||
def test_erc721_reject(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
common_test_nft_reject(test_erc721,
|
||||
firmware,
|
||||
backend,
|
||||
scenario_navigator,
|
||||
default_screenshot_path,
|
||||
collecs_721[0],
|
||||
actions_721[0])
|
||||
|
||||
@@ -237,14 +230,12 @@ def action_1155_fixture(request) -> Action:
|
||||
def test_erc1155(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
collec_1155: NFTCollection,
|
||||
action_1155: Action,
|
||||
reject: bool = False):
|
||||
common_test_nft(firmware,
|
||||
backend,
|
||||
scenario_navigator,
|
||||
default_screenshot_path,
|
||||
collec_1155,
|
||||
action_1155,
|
||||
reject,
|
||||
@@ -253,12 +244,10 @@ def test_erc1155(firmware: Firmware,
|
||||
|
||||
def test_erc1155_reject(firmware: Firmware,
|
||||
backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path):
|
||||
scenario_navigator: NavigateWithScenario):
|
||||
common_test_nft_reject(test_erc1155,
|
||||
firmware,
|
||||
backend,
|
||||
scenario_navigator,
|
||||
default_screenshot_path,
|
||||
collecs_1155[0],
|
||||
actions_1155[0])
|
||||
|
||||
@@ -46,18 +46,18 @@ def common(firmware: Firmware,
|
||||
_, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
|
||||
|
||||
with app_client.sign(path, tx_params):
|
||||
if not firmware.device.startswith("nano") and confirm:
|
||||
if not firmware.is_nano and confirm:
|
||||
navigator.navigate_and_compare(default_screenshot_path,
|
||||
f"{test_name}/confirm",
|
||||
[NavInsID.USE_CASE_CHOICE_CONFIRM],
|
||||
screen_change_after_last_instruction=False)
|
||||
|
||||
if firmware.device.startswith("nano"):
|
||||
if firmware.is_nano:
|
||||
end_text = "Accept"
|
||||
else:
|
||||
end_text = "Sign"
|
||||
|
||||
scenario_navigator.review_approve(default_screenshot_path, test_name, end_text, (test_name != ""))
|
||||
scenario_navigator.review_approve(custom_screen_text=end_text, do_comparison=test_name!="")
|
||||
|
||||
# verify signature
|
||||
vrs = ResponseParser.signature(app_client.response().data)
|
||||
@@ -67,15 +67,13 @@ def common(firmware: Firmware,
|
||||
|
||||
def common_reject(backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
default_screenshot_path: Path,
|
||||
tx_params: dict,
|
||||
test_name: str,
|
||||
path: str = BIP32_PATH):
|
||||
app_client = EthAppClient(backend)
|
||||
|
||||
try:
|
||||
with app_client.sign(path, tx_params):
|
||||
scenario_navigator.review_reject(default_screenshot_path, test_name)
|
||||
scenario_navigator.review_reject()
|
||||
|
||||
except ExceptionRAPDU as e:
|
||||
assert e.status == StatusWord.CONDITION_NOT_SATISFIED
|
||||
@@ -235,10 +233,7 @@ def test_sign_nonce_display(firmware: Firmware,
|
||||
common(firmware, backend, navigator, scenario_navigator, default_screenshot_path, tx_params, test_name, "m/44'/60'/1'/0/0")
|
||||
|
||||
|
||||
def test_sign_reject(backend: BackendInterface,
|
||||
scenario_navigator: NavigateWithScenario,
|
||||
test_name: str,
|
||||
default_screenshot_path: Path):
|
||||
def test_sign_reject(backend: BackendInterface, scenario_navigator: NavigateWithScenario):
|
||||
tx_params: dict = {
|
||||
"nonce": NONCE2,
|
||||
"gasPrice": Web3.to_wei(GAS_PRICE, 'gwei'),
|
||||
@@ -247,7 +242,7 @@ def test_sign_reject(backend: BackendInterface,
|
||||
"value": Web3.to_wei(AMOUNT2, "ether"),
|
||||
"chainId": CHAIN_ID
|
||||
}
|
||||
common_reject(backend, scenario_navigator, default_screenshot_path, tx_params, test_name, "m/44'/60'/1'/0/0")
|
||||
common_reject(backend, scenario_navigator, tx_params, "m/44'/60'/1'/0/0")
|
||||
|
||||
|
||||
def test_sign_error_transaction_type(backend: BackendInterface):
|
||||
|
||||
12
tools/copy_clones.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEVICES=(nanos nanos2 nanox stax flex)
|
||||
|
||||
for dev in "${DEVICES[@]}"; do
|
||||
elf_file="build/${dev}/bin/app.elf"
|
||||
if [[ -f ${elf_file} ]]; then
|
||||
cp "${elf_file}" "tests/ragger/.test_dependencies/clone/build/${dev}/bin/"
|
||||
else
|
||||
echo "Ignoring unknown file/dev: ${elf_file}"
|
||||
fi
|
||||
done
|
||||