From 54659d49d85024898d2fd31c4db9da12b4ae96f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 15 Nov 2017 15:42:56 +0100 Subject: [PATCH] layout: op_return now requires confirmation by user --- firmware/layout2.c | 80 ++++++++++++++++++++++++++++++------------ firmware/layout2.h | 1 + firmware/transaction.c | 6 ++++ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 9dafb8d43f..dfe4d93098 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -36,6 +36,33 @@ #define BITCOIN_DIVISIBILITY (8) +// split longer string into 4 rows, rowlen chars each +static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) +{ + static char str[4][32 + 1]; + if (rowlen > 32) { + rowlen = 32; + } + memset(str, 0, sizeof(str)); + strlcpy(str[0], (char *)msg, rowlen + 1); + if (len > rowlen) { + strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); + } + if (len > rowlen * 2) { + strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); + } + if (len > rowlen * 3) { + strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); + } + if (len > rowlen * 4) { + str[3][rowlen - 1] = '.'; + str[3][rowlen - 2] = '.'; + str[3][rowlen - 3] = '.'; + } + static const char *ret[4] = { str[0], str[1], str[2], str[3] }; + return ret; +} + void *layoutLast = layoutHome; void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) @@ -128,6 +155,37 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) ); } +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) +{ + bool ascii_only = true; + for (uint32_t i = 0; i < size; i++) { + if (data[i] < ' ' || data[i] > '~') { + ascii_only = false; + break; + } + } + const char **str; + if (!ascii_only) { + char hex[65]; + memset(hex, 0, sizeof(hex)); + data2hex(data, (size > 32) ? 32 : size, hex); + str = split_message((const uint8_t *)hex, size * 2, 16); + } else { + str = split_message(data, size, 20); + } + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + NULL, + _("Confirm OP_RETURN:"), + str[0], + str[1], + str[2], + str[3], + NULL + ); +} + void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee) { char str_out[32], str_fee[32]; @@ -163,28 +221,6 @@ void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) ); } -// split longer string into 4 rows, rowlen chars each -static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) -{ - static char str[4][32 + 1]; - if (rowlen > 32) { - rowlen = 32; - } - memset(str, 0, sizeof(str)); - strlcpy(str[0], (char *)msg, rowlen + 1); - if (len > rowlen) { - strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); - } - if (len > rowlen * 2) { - strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); - } - if (len > rowlen * 3) { - strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); - } - static const char *ret[4] = { str[0], str[1], str[2], str[3] }; - return ret; -} - void layoutSignMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); diff --git a/firmware/layout2.h b/firmware/layout2.h index 48e001fb94..2c523a242e 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -41,6 +41,7 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); diff --git a/firmware/transaction.c b/firmware/transaction.c index 40a872d0a3..a5740e8725 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -171,6 +171,12 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T if (in->amount != 0) { return 0; // failed to compile output } + if (needs_confirm) { + layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; // user aborted + } + } uint32_t r = 0; out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r);