diff --git a/deps/ledger-zxlib/app/common/view.c b/deps/ledger-zxlib/app/common/view.c new file mode 100644 index 00000000..bf012980 --- /dev/null +++ b/deps/ledger-zxlib/app/common/view.c @@ -0,0 +1,162 @@ +/******************************************************************************* +* (c) 2018, 2019 Zondax GmbH +* (c) 2016 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "view.h" +#include "coin.h" +#include "view_internal.h" +#include "crypto.h" + +#include "actions.h" +#include "apdu_codes.h" +#include "glyphs.h" +#include "bagl.h" +#include "zxmacros.h" +#include "view_templates.h" +#include "tx.h" + +#include +#include + +view_t viewdata; + +void h_address_accept(unsigned int _) { + UNUSED(_); + view_idle_show(0); + UX_WAIT(); + app_reply_address(); +} + +void h_error_accept(unsigned int _) { + UNUSED(_); + view_idle_show(0); + UX_WAIT(); + app_reply_address(); +} + +void h_sign_accept(unsigned int _) { + UNUSED(_); + + const uint8_t replyLen = app_sign(); + + view_idle_show(0); + UX_WAIT(); + + if (replyLen > 0) { + set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2); + } else { + set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + } +} + +void h_sign_reject(unsigned int _) { + UNUSED(_); + view_idle_show(0); + UX_WAIT(); + + set_code(G_io_apdu_buffer, 0, APDU_CODE_COMMAND_NOT_ALLOWED); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); +} + +void h_review_init() { + viewdata.idx = 0; + viewdata.pageIdx = 0; + viewdata.pageCount = 1; +} + +void h_review_increase() { + viewdata.pageIdx++; + if (viewdata.pageIdx >= viewdata.pageCount) { + viewdata.idx++; + viewdata.pageIdx = 0; + } +} + +void h_review_decrease() { + viewdata.pageIdx--; + if (viewdata.pageIdx < 0) { + viewdata.idx--; + viewdata.pageIdx = 0; + } +} + +view_error_t h_review_update_data() { + tx_error_t err = tx_no_error; + + do { + err = tx_getItem(viewdata.idx, + viewdata.key, MAX_CHARS_PER_KEY_LINE, + viewdata.value, MAX_CHARS_PER_VALUE1_LINE, + viewdata.pageIdx, &viewdata.pageCount); + + if (err == tx_no_data) { + return view_no_data; + } + + if (viewdata.pageCount == 0) { + h_review_increase(); + } + } while (viewdata.pageCount == 0); + + if (err != tx_no_error) { + return view_error_detected; + } + + splitValueField(); + return view_no_error; +} + +view_error_t h_addr_update_item(uint8_t idx) { + MEMZERO(viewdata.addr, MAX_CHARS_ADDR); + switch (idx) { + case 0: + snprintf(viewdata.addr, MAX_CHARS_ADDR, "%s", (char *) (G_io_apdu_buffer + VIEW_ADDRESS_BUFFER_OFFSET)); + break; + case 1: + bip32_to_str(viewdata.addr, MAX_CHARS_ADDR, hdPath, HDPATH_LEN_DEFAULT); + break; + } + return view_no_error; +} + +void io_seproxyhal_display(const bagl_element_t *element) { + io_seproxyhal_display_default((bagl_element_t *) element); +} + +void view_init(void) { + UX_INIT(); +} + +void view_idle_show(unsigned int ignored) { + view_idle_show_impl(); +} + +void view_address_show() { + view_address_show_impl(); +} + +void view_error_show() { + snprintf(viewdata.key, MAX_CHARS_PER_KEY_LINE, "ERROR"); + snprintf(viewdata.value, MAX_CHARS_PER_VALUE1_LINE, "SHOWING DATA"); + splitValueField(); + view_error_show_impl(); +} + +void view_sign_show() { + view_sign_show_impl(); +} diff --git a/deps/ledger-zxlib/app/common/view.h b/deps/ledger-zxlib/app/common/view.h new file mode 100644 index 00000000..1908dcdf --- /dev/null +++ b/deps/ledger-zxlib/app/common/view.h @@ -0,0 +1,42 @@ +/******************************************************************************* +* (c) 2018-2020 Zondax GmbH +* (c) 2016 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#include + +#if defined(LEDGER_SPECIFIC) +#include "bolos_target.h" +#if defined(BOLOS_SDK) +#include "os.h" +#include "cx.h" +#endif +#endif + +/// view_init (initializes UI) +void view_init(); + +/// view_idle_show (idle view - main menu + status) +void view_idle_show(unsigned int ignored); + +/// view_error (error view) +void view_error_show(); + +// shows address in the screen +void view_address_show(); + +// Shows review screen + later sign menu +void view_sign_show(); diff --git a/deps/ledger-zxlib/app/common/view_internal.h b/deps/ledger-zxlib/app/common/view_internal.h new file mode 100644 index 00000000..1775eafc --- /dev/null +++ b/deps/ledger-zxlib/app/common/view_internal.h @@ -0,0 +1,108 @@ +/******************************************************************************* +* (c) 2019 Zondax GmbH +* (c) 2016 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#include +#include "coin.h" + +#define CUR_FLOW G_ux.flow_stack[G_ux.stack_count-1] + +#if defined(TARGET_NANOX) +#define MAX_CHARS_PER_KEY_LINE 64 +#define MAX_CHARS_PER_VALUE1_LINE 4096 +#define MAX_CHARS_HEXMESSAGE 160 +#else +#define MAX_CHARS_PER_KEY_LINE (32+1) +#define MAX_CHARS_PER_VALUE_LINE (18) +#define MAX_CHARS_PER_VALUE1_LINE (2*MAX_CHARS_PER_VALUE_LINE+1) +#define MAX_CHARS_PER_VALUE2_LINE (MAX_CHARS_PER_VALUE_LINE+1) +#define MAX_CHARS_HEXMESSAGE 40 +#endif +#define MAX_CHARS_ADDR (MAX_CHARS_PER_KEY_LINE + MAX_CHARS_PER_VALUE1_LINE) + +// This typically will point to G_io_apdu_buffer that is prefilled with the address + +typedef struct { + union { + struct { + char key[MAX_CHARS_PER_KEY_LINE]; + char value[MAX_CHARS_PER_VALUE1_LINE]; +#if defined(TARGET_NANOS) + char value2[MAX_CHARS_PER_VALUE2_LINE]; +#endif + }; + struct { + char addr[MAX_CHARS_ADDR]; + }; + }; + int8_t idx; + int8_t pageIdx; + uint8_t pageCount; +} view_t; + +extern view_t viewdata; + +typedef enum { + view_no_error = 0, + view_no_data = 1, + view_error_detected = 2 +} view_error_t; + +#define print_title(...) snprintf(viewdata.title, sizeof(viewdata.title), __VA_ARGS__) +#define print_key(...) snprintf(viewdata.key, sizeof(viewdata.key), __VA_ARGS__); +#define print_value(...) snprintf(viewdata.value, sizeof(viewdata.value), __VA_ARGS__); + +#if defined(TARGET_NANOS) +#define print_value2(...) snprintf(viewdata.value2, sizeof(viewdata.value2), __VA_ARGS__); +#endif + +void splitValueField(); + +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// + +void view_idle_show_impl(); + +void view_address_show_impl(); + +void view_error_show_impl(); + +void view_sign_show_impl(); + +void h_address_accept(unsigned int _); + +void h_error_accept(unsigned int _); + +void h_sign_accept(unsigned int _); + +void h_sign_reject(unsigned int _); + +void h_review_init(); + +void h_review_increase(); + +void h_review_decrease(); + +view_error_t h_review_update_data(); + +view_error_t h_addr_update_item(uint8_t idx); diff --git a/deps/ledger-zxlib/app/common/view_s.c b/deps/ledger-zxlib/app/common/view_s.c new file mode 100644 index 00000000..58b91d7f --- /dev/null +++ b/deps/ledger-zxlib/app/common/view_s.c @@ -0,0 +1,234 @@ +/******************************************************************************* +* (c) 2018, 2019 Zondax GmbH +* (c) 2016 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "view.h" +#include "view_internal.h" +#include "actions.h" +#include "apdu_codes.h" +#include "glyphs.h" +#include "bagl.h" +#include "zxmacros.h" +#include "view_templates.h" +#include "tx.h" + +#include +#include + +#if defined(TARGET_NANOS) + +void h_review_button_left(); +void h_review_button_right(); +void view_review_show(); +void view_sign_show_s(); + +ux_state_t ux; + +void os_exit(uint32_t id) { + os_sched_exit(0); +} + +const ux_menu_entry_t menu_main[] = { + {NULL, NULL, 0, &C_icon_app, MENU_MAIN_APP_LINE1, MENU_MAIN_APP_LINE2, 33, 12}, + {NULL, NULL, 0, NULL, "v"APPVERSION, NULL, 0, 0}, + {NULL, os_exit, 0, &C_icon_dashboard, "Quit", NULL, 50, 29}, + UX_MENU_END +}; + +UX_STEP_NOCB_INIT(ux_addr_flow_1_step, paging, + { h_addr_update_item(CUR_FLOW.index); }, + { .title = "Address", .text = viewdata.addr, }); +UX_STEP_NOCB_INIT(ux_addr_flow_2_step, paging, + { h_addr_update_item(CUR_FLOW.index); }, + { .title = "Path", .text = viewdata.addr, }); +UX_STEP_VALID(ux_addr_flow_3_step, pb, h_address_accept(0), { &C_icon_validate_14, "Ok"}); + +UX_FLOW( + ux_addr_flow, + &ux_addr_flow_1_step, + &ux_addr_flow_2_step, + &ux_addr_flow_3_step +); + +void h_review(unsigned int _) { UNUSED(_); view_sign_show_impl(); } + +const ux_menu_entry_t menu_sign[] = { + {NULL, h_review, 0, NULL, "View transaction", NULL, 0, 0}, + {NULL, h_sign_accept, 0, NULL, "Sign transaction", NULL, 0, 0}, + {NULL, h_sign_reject, 0, &C_icon_back, "Reject", NULL, 60, 40}, + UX_MENU_END +}; + +static const bagl_element_t view_review[] = { + UI_BACKGROUND_LEFT_RIGHT_ICONS, + UI_LabelLine(UIID_LABEL + 0, 0, 8, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.key), + UI_LabelLine(UIID_LABEL + 1, 0, 19, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value), + UI_LabelLine(UIID_LABEL + 2, 0, 30, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value2), +}; + +static const bagl_element_t view_error[] = { + UI_FillRectangle(0, 0, 0, UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 0x000000, 0xFFFFFF), + UI_Icon(0, 128 - 7, 0, 7, 7, BAGL_GLYPH_ICON_CHECK), + UI_LabelLine(UIID_LABEL + 0, 0, 8, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.key), + UI_LabelLine(UIID_LABEL + 0, 0, 19, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value), + UI_LabelLineScrolling(UIID_LABELSCROLL, 0, 30, 128, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value2), +}; + +static unsigned int view_error_button(unsigned int button_mask, unsigned int button_mask_counter) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + h_error_accept(0); + break; + } + return 0; +} + +static unsigned int view_review_button(unsigned int button_mask, unsigned int button_mask_counter) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: + // Press both left and right buttons to quit + view_sign_show_s(); + break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + // Press left to progress to the previous element + h_review_button_left(); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + // Press right to progress to the next element + h_review_button_right(); + break; + } + return 0; +} + +const bagl_element_t *view_prepro(const bagl_element_t *element) { + switch (element->component.userid) { + case UIID_ICONLEFT: + case UIID_ICONRIGHT: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case UIID_LABELSCROLL: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7)) + ); + break; + } + return element; +} + +void h_review_button_left() { + h_review_decrease(); + + view_error_t err = h_review_update_data(); + switch(err) { + case view_no_error: + view_review_show(); + break; + case view_no_data: + view_sign_show_s(); + break; + case view_error_detected: + default: + view_error_show(); + break; + } + + UX_WAIT(); +} + +void h_review_button_right() { + h_review_increase(); + + view_error_t err = h_review_update_data(); + + switch(err) { + case view_no_error: + view_review_show(); + break; + case view_no_data: + view_sign_show_s(); + break; + case view_error_detected: + default: + view_error_show(); + break; + } + + UX_WAIT(); +} + +void splitValueField() { + print_value2(""); + uint16_t vlen = strlen(viewdata.value); + if (vlen > MAX_CHARS_PER_VALUE2_LINE - 1) { + strcpy(viewdata.value2, viewdata.value + MAX_CHARS_PER_VALUE_LINE); + viewdata.value[MAX_CHARS_PER_VALUE_LINE] = 0; + } +} + +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// + +void view_idle_show_impl() { + UX_MENU_DISPLAY(0, menu_main, NULL); +} + +void view_address_show_impl() { + ux_layout_paging_reset(); + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_addr_flow, NULL); +} + +void view_error_show_impl() { + UX_DISPLAY(view_error, view_prepro); +} + +void view_sign_show_impl() { + h_review_init(); + + view_error_t err = h_review_update_data(); + switch(err) { + case view_no_error: + view_review_show(); + break; + case view_no_data: + view_sign_show_s(); + break; + case view_error_detected: + default: + view_error_show(); + break; + } +} + +void view_sign_show_s(void){ + UX_MENU_DISPLAY(0, menu_sign, NULL); +} + +void view_review_show() { + UX_DISPLAY(view_review, view_prepro); +} + +#endif diff --git a/deps/ledger-zxlib/app/common/view_x.c b/deps/ledger-zxlib/app/common/view_x.c new file mode 100644 index 00000000..c3519e03 --- /dev/null +++ b/deps/ledger-zxlib/app/common/view_x.c @@ -0,0 +1,227 @@ +/******************************************************************************* +* (c) 2018, 2019 Zondax GmbH +* (c) 2016 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "view.h" +#include "view_internal.h" +#include "actions.h" +#include "apdu_codes.h" +#include "glyphs.h" +#include "bagl.h" +#include "zxmacros.h" +#include "view_templates.h" +#include "tx.h" + +#include +#include + +#if defined(TARGET_NANOX) + +void h_review_loop_start(); +void h_review_loop_inside(); +void h_review_loop_end(); + +#include "ux.h" +ux_state_t G_ux; +bolos_ux_params_t G_ux_params; +uint8_t flow_inside_loop; + +UX_FLOW_DEF_NOCB(ux_idle_flow_1_step, pbb, { &C_icon_app, MENU_MAIN_APP_LINE1, MENU_MAIN_APP_LINE2,}); +UX_FLOW_DEF_NOCB(ux_idle_flow_3_step, bn, { "Version", APPVERSION, }); +UX_FLOW_DEF_VALID(ux_idle_flow_4_step, pb, os_sched_exit(-1), { &C_icon_dashboard, "Quit",}); +const ux_flow_step_t *const ux_idle_flow [] = { + &ux_idle_flow_1_step, + &ux_idle_flow_3_step, + &ux_idle_flow_4_step, + FLOW_END_STEP, +}; + +/////////// + +UX_STEP_NOCB_INIT(ux_addr_flow_1_step, bnnn_paging, + { h_addr_update_item(CUR_FLOW.index); }, + { .title = "Address", .text = viewdata.addr, }); +UX_STEP_NOCB_INIT(ux_addr_flow_2_step, bnnn_paging, + { h_addr_update_item(CUR_FLOW.index); }, + { .title = "Path", .text = viewdata.addr, }); +UX_STEP_VALID(ux_addr_flow_3_step, pb, h_address_accept(0), { &C_icon_validate_14, "Ok"}); + +UX_FLOW( + ux_addr_flow, + &ux_addr_flow_1_step, + &ux_addr_flow_2_step, + &ux_addr_flow_3_step +); + +/////////// + +UX_STEP_NOCB(ux_error_flow_1_step, bnnn_paging, { .title = viewdata.key, .text = viewdata.value, }); +UX_STEP_VALID(ux_error_flow_2_step, pb, h_error_accept(0), { &C_icon_validate_14, "Ok"}); + +UX_FLOW( + ux_error_flow, + &ux_error_flow_1_step, + &ux_error_flow_2_step +); + +/////////// +UX_STEP_NOCB(ux_sign_flow_1_step, pbb, { &C_icon_eye, "View", "Transaction" }); + +UX_STEP_INIT(ux_sign_flow_2_start_step, NULL, NULL, { h_review_loop_start(); }); +UX_STEP_NOCB_INIT(ux_sign_flow_2_step, bnnn_paging, { h_review_loop_inside(); }, { .title = viewdata.key, .text = viewdata.value, }); +UX_STEP_INIT(ux_sign_flow_2_end_step, NULL, NULL, { h_review_loop_end(); }); + +UX_STEP_VALID(ux_sign_flow_3_step, pbb, h_sign_accept(0), { &C_icon_validate_14, "Sign", "Transaction" }); +UX_STEP_VALID(ux_sign_flow_4_step, pbb, h_sign_reject(0), { &C_icon_crossmark, "Reject", "Transaction" }); +const ux_flow_step_t *const ux_sign_flow[] = { + &ux_sign_flow_1_step, + &ux_sign_flow_2_start_step, + &ux_sign_flow_2_step, + &ux_sign_flow_2_end_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step, + FLOW_END_STEP, +}; + +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// + +void h_review_loop_start() { + if (flow_inside_loop) { + // coming from right + h_review_decrease(); + if (viewdata.idx<0) { + // exit to the left + flow_inside_loop = 0; + ux_flow_prev(); + return; + } + } else { + // coming from left + h_review_init(); + } + + view_error_t err = h_review_update_data(); + switch(err) { + case view_no_error: + case view_no_data: + break; + case view_error_detected: + default: + view_error_show(); + break; + } + + ux_flow_next(); +} + +void h_review_loop_inside() { + flow_inside_loop = 1; +} + +void h_review_loop_end() { + if (flow_inside_loop) { + // coming from left + h_review_increase(); + view_error_t err = h_review_update_data(); + + switch(err) { + case view_no_error: + ux_layout_bnnn_paging_reset(); + break; + case view_no_data: { + flow_inside_loop = 0; + ux_flow_next(); + return; + } + case view_error_detected: + default: + view_error_show(); + break; + } + } else { + // coming from right + h_review_decrease(); + view_error_t err = h_review_update_data(); + + switch(err) { + case view_no_error: + case view_no_data: + break; + case view_error_detected: + default: + view_error_show(); + break; + } + } + + // move to prev flow but trick paging to show first page + CUR_FLOW.prev_index = CUR_FLOW.index-2; + CUR_FLOW.index--; + ux_flow_relayout(); +} + +void splitValueField() { + uint16_t vlen = strlen(viewdata.value); + if (vlen == 0 ) { + strcpy(viewdata.value, " "); + } +} + +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// +////////////////////////// + +void view_idle_show_impl() { + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); +} + +void view_address_show_impl() { + ux_layout_bnnn_paging_reset(); + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_addr_flow, NULL); +} + +void view_error_show_impl() { + ux_layout_bnnn_paging_reset(); + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_error_flow, NULL); +} + +void view_sign_show_impl(){ + h_review_init(); + h_review_decrease(); + //// + flow_inside_loop = 0; + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_sign_flow, NULL); +} + +#endif