From aeb8718bc2b1ac090ed620d38cf7edaf72bc4de2 Mon Sep 17 00:00:00 2001 From: Nicolas Roggeman Date: Mon, 27 May 2024 10:10:46 +0200 Subject: [PATCH] Enable bling warning indication for reviews, to warn user in some cases. --- lib_nbgl/include/nbgl_page.h | 5 ++- lib_nbgl/src/nbgl_layout.c | 24 +++++------ lib_nbgl/src/nbgl_layout_internal.h | 10 +++++ lib_nbgl/src/nbgl_layout_keyboard.c | 3 +- lib_nbgl/src/nbgl_layout_keypad.c | 3 +- lib_nbgl/src/nbgl_page.c | 4 ++ lib_nbgl/src/nbgl_use_case.c | 64 ++++++++++++++++++++++++++++- 7 files changed, 94 insertions(+), 19 deletions(-) diff --git a/lib_nbgl/include/nbgl_page.h b/lib_nbgl/include/nbgl_page.h index 64af7ec84..5a7f51338 100644 --- a/lib_nbgl/include/nbgl_page.h +++ b/lib_nbgl/include/nbgl_page.h @@ -55,7 +55,10 @@ typedef struct nbgl_pageContent_s { uint8_t titleToken; ///< if isTouchableTitle set to true, this is the token used when touching ///< title tune_index_e tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played when title is touched - nbgl_contentType_t type; ///< type of page content in the following union + uint8_t topRightToken; ///< token used when top-right button (if not NULL) is touched + const nbgl_icon_details_t *topRightIcon; ///< a buffer containing the 32px/40px icon for icon + ///< on top-right of screen (no button if NULL) + nbgl_contentType_t type; ///< type of page content in the following union union { nbgl_contentCenteredInfo_t centeredInfo; ///< @ref CENTERED_INFO type nbgl_contentInfoLongPress_t infoLongPress; ///< @ref INFO_LONG_PRESS type diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index f51f7d8de..fd3f0a081 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -37,9 +37,6 @@ // used by container #define NB_MAX_CONTAINER_CHILDREN 20 -// used by screen -#define NB_MAX_SCREEN_CHILDREN 7 - #define TAG_VALUE_ICON_WIDTH 32 #ifdef TARGET_STAX @@ -755,9 +752,11 @@ nbgl_layout_t *nbgl_layoutGet(const nbgl_layoutDescription_t *description) layout->container->obj.area.height = SCREEN_HEIGHT; layout->container->layout = VERTICAL; layout->container->children = nbgl_containerPoolGet(NB_MAX_CONTAINER_CHILDREN, layout->layer); + // by default, if no header, main container is aligned on top-left + layout->container->obj.alignment = TOP_LEFT; // main container is always the second object, leaving space for header - layout->children[1] = (nbgl_obj_t *) layout->container; - layout->nbChildren = 2; + layout->children[MAIN_CONTAINER_INDEX] = (nbgl_obj_t *) layout->container; + layout->nbChildren = NB_MAX_SCREEN_CHILDREN; // if a tap text is defined, make the container tapable and display this text in gray if (description->tapActionText != NULL) { @@ -877,8 +876,7 @@ int nbgl_layoutAddTopRightButton(nbgl_layout_t *layout, button->obj.alignment = TOP_RIGHT; // add to screen - layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) button; - layoutInt->nbChildren++; + layoutInt->children[TOP_RIGHT_BUTTON_INDEX] = (nbgl_obj_t *) button; return 0; } @@ -2486,10 +2484,12 @@ int nbgl_layoutAddHeader(nbgl_layout_t *layout, const nbgl_layoutHeader_t *heade layoutInt->headerContainer->nbChildren++; } // header must be the first child - layoutInt->children[0] = (nbgl_obj_t *) layoutInt->headerContainer; + layoutInt->children[HEADER_INDEX] = (nbgl_obj_t *) layoutInt->headerContainer; // subtract header height from main container height layoutInt->container->obj.area.height -= layoutInt->headerContainer->obj.area.height; + layoutInt->container->obj.alignTo = (nbgl_obj_t *) layoutInt->headerContainer; + layoutInt->container->obj.alignment = BOTTOM_LEFT; layoutInt->headerType = headerDesc->type; @@ -2920,8 +2920,7 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_ layoutInt->footerContainer->nbChildren++; } - layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) layoutInt->footerContainer; - layoutInt->nbChildren++; + layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer; // subtract footer height from main container height layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height; @@ -3054,9 +3053,8 @@ int nbgl_layoutDraw(nbgl_layout_t *layoutParam) } if (layout->withLeftBorder == true) { // draw now the line - nbgl_line_t *line = createLeftVerticalLine(layout->layer); - layout->children[layout->nbChildren] = (nbgl_obj_t *) line; - layout->nbChildren++; + nbgl_line_t *line = createLeftVerticalLine(layout->layer); + layout->children[LEFT_BORDER_INDEX] = (nbgl_obj_t *) line; } nbgl_screenRedraw(); diff --git a/lib_nbgl/src/nbgl_layout_internal.h b/lib_nbgl/src/nbgl_layout_internal.h index cbff2384c..5b20c1160 100644 --- a/lib_nbgl/src/nbgl_layout_internal.h +++ b/lib_nbgl/src/nbgl_layout_internal.h @@ -51,6 +51,16 @@ typedef enum { NB_SWIPE_USAGE } nbgl_swipe_usage_t; +// used by screen (top level) +enum { + HEADER_INDEX = 0, // For header container + TOP_RIGHT_BUTTON_INDEX, + MAIN_CONTAINER_INDEX, + LEFT_BORDER_INDEX, + FOOTER_INDEX, + NB_MAX_SCREEN_CHILDREN +}; + /** * @brief Structure containing all information about the current layout. * @note It shall not be used externally diff --git a/lib_nbgl/src/nbgl_layout_keyboard.c b/lib_nbgl/src/nbgl_layout_keyboard.c index 338625d72..5228f5247 100644 --- a/lib_nbgl/src/nbgl_layout_keyboard.c +++ b/lib_nbgl/src/nbgl_layout_keyboard.c @@ -497,8 +497,7 @@ int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInf layoutInt->footerContainer->nbChildren = 1; // add footer to layout children - layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) layoutInt->footerContainer; - layoutInt->nbChildren++; + layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer; // subtract footer height from main container height layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height; diff --git a/lib_nbgl/src/nbgl_layout_keypad.c b/lib_nbgl/src/nbgl_layout_keypad.c index 2c0e40f64..d1e9126e1 100644 --- a/lib_nbgl/src/nbgl_layout_keypad.c +++ b/lib_nbgl/src/nbgl_layout_keypad.c @@ -102,8 +102,7 @@ int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, boo layoutInt->footerContainer->nbChildren++; // add to layout children - layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) layoutInt->footerContainer; - layoutInt->nbChildren++; + layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer; // subtract footer height from main container height layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height; diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index 7d4953a18..7e44ff5cb 100644 --- a/lib_nbgl/src/nbgl_page.c +++ b/lib_nbgl/src/nbgl_page.c @@ -41,6 +41,10 @@ static void addContent(nbgl_pageContent_t *content, .backAndText.text = content->title}; nbgl_layoutAddHeader(layout, &headerDesc); } + if (content->topRightIcon != NULL) { + nbgl_layoutAddTopRightButton( + layout, content->topRightIcon, content->topRightToken, content->tuneId); + } switch (content->type) { case INFO_LONG_PRESS: { nbgl_layoutCenteredInfo_t centeredInfo; diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c index 121d4c7fd..f980f4d1d 100644 --- a/lib_nbgl/src/nbgl_use_case.c +++ b/lib_nbgl/src/nbgl_use_case.c @@ -63,7 +63,8 @@ enum { DETAILS_BUTTON_TOKEN, CONFIRM_TOKEN, REJECT_TOKEN, - VALUE_ALIAS_TOKEN + VALUE_ALIAS_TOKEN, + BLIND_WARNING_TOKEN }; typedef enum { @@ -234,6 +235,7 @@ static char reducedAddress[QRCODE_REDUCED_ADDR_LEN]; static void displayReviewPage(uint8_t page, bool forceFullRefresh); static void displayDetailsPage(uint8_t page, bool forceFullRefresh); static void displayFullValuePage(const nbgl_contentTagValue_t *pair); +static void displayBlindWarning(nbgl_opType_t opType); static void displaySettingsPage(uint8_t page, bool forceFullRefresh); static void displayGenericContextPage(uint8_t pageIdx, bool forceFullRefresh); static void pageCallback(int token, uint8_t index); @@ -563,6 +565,16 @@ static void pageCallback(int token, uint8_t index) } displayFullValuePage(pair); } + else if (token == BLIND_WARNING_TOKEN) { + if (navType == STREAMING_NAV) { + displayBlindWarning(bundleNavContext.reviewStreaming.operationType + & ~(SKIPPABLE_OPERATION | BLIND_OPERATION)); + } + else { + displayBlindWarning(bundleNavContext.review.operationType + & ~(SKIPPABLE_OPERATION | BLIND_OPERATION)); + } + } else { // probably a control provided by caller if (onContentAction != NULL) { onContentAction(token, index, navInfo.activePage); @@ -943,6 +955,15 @@ static bool genericContextPreparePageContent(const nbgl_content_t *p_content, LOG_DEBUG(USE_CASE_LOGGER, "Unsupported type %d\n", pageContent->type); return false; } + // if first or last page of review and blind operation, add the top-right button + if (((p_content == &STARTING_CONTENT) || (p_content->type == INFO_LONG_PRESS)) + && (((navType == STREAMING_NAV) + && (bundleNavContext.reviewStreaming.operationType & BLIND_OPERATION)) + || ((navType == GENERIC_NAV) + && (bundleNavContext.review.operationType & BLIND_OPERATION)))) { + pageContent->topRightIcon = &WARNING_ICON; + pageContent->topRightToken = BLIND_WARNING_TOKEN; + } return true; } @@ -1063,6 +1084,7 @@ static void displayDetailsPage(uint8_t detailsPage, bool forceFullRefresh) .progressIndicator = true, .tuneId = TUNE_TAP_CASUAL}; nbgl_pageContent_t content = {.type = TAG_VALUE_LIST, + .topRightIcon = NULL, .tagValueList.nbPairs = 1, .tagValueList.pairs = ¤tPair, .tagValueList.smallCaseForValue = true, @@ -1158,6 +1180,46 @@ static void displayFullValuePage(const nbgl_contentTagValue_t *pair) nbgl_refresh(); } +// function used to display the modal warning when touching the alert symbol of a blind review +static void displayBlindWarning(nbgl_opType_t opType) +{ + nbgl_layoutDescription_t layoutDescription = {.modal = true, + .withLeftBorder = true, + .onActionCallback = &modalLayoutTouchCallback, + .tapActionText = NULL}; + nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT, + .separationLine = false, + .backAndText.token = 0, + .backAndText.tuneId = TUNE_TAP_CASUAL, + .backAndText.text = NULL}; + nbgl_layoutCenteredInfo_t centeredInfo + = {.icon = NULL, .text3 = NULL, .style = LARGE_CASE_INFO, .offsetY = 0, .onTop = false}; + if (opType == TYPE_TRANSACTION) { + centeredInfo.text1 = "This transaction cannot be trusted"; + centeredInfo.text2 + = "Your Ledger cannot decode this transaction. If you sign it, you could be " + "authorizing " + "malicious actions that can drain your wallet.\n\n" + "Learn more: ledger.com/e8"; + } + else { + centeredInfo.text1 = "This message cannot be trusted"; + centeredInfo.text2 + = "Your Ledger cannot decode this message. If you sign it, you could be authorizing " + "malicious actions that can drain your wallet.\n\n" + "Learn more: ledger.com/e8"; + } + genericContext.modalLayout = nbgl_layoutGet(&layoutDescription); + // add header with the tag part of the pair, to go back + nbgl_layoutAddHeader(genericContext.modalLayout, &headerDesc); + // add full value text + nbgl_layoutAddCenteredInfo(genericContext.modalLayout, ¢eredInfo); + + // draw & refresh + nbgl_layoutDraw(genericContext.modalLayout); + nbgl_refresh(); +} + #ifdef NBGL_QRCODE static void displayAddressQRCode(void) {