Better split between business logic & UI code for EIP-712

This commit is contained in:
Alexandre Paillier
2022-10-21 18:00:59 +02:00
parent 109dffc70e
commit c158c3e502
7 changed files with 160 additions and 151 deletions

View File

@@ -25,6 +25,11 @@ void ui_191_switch_to_message_end(void);
void ui_191_switch_to_sign(void);
void ui_191_switch_to_question(void);
// EIP-712
void ui_712_start(void);
void ui_712_switch_to_message(void);
void ui_712_switch_to_sign(void);
#include "ui_callbacks.h"
#include <string.h>

View File

@@ -1,57 +0,0 @@
#ifdef HAVE_EIP712_FULL_SUPPORT
#include "ui_flow_712.h"
#include "ui_logic.h"
#include "shared_context.h" // strings
// clang-format off
UX_STEP_NOCB(
ux_712_step_review,
pnn,
{
&C_icon_eye,
"Review",
"typed message",
});
UX_STEP_NOCB(
ux_712_step_dynamic,
bnnn_paging,
{
.title = strings.tmp.tmp2,
.text = strings.tmp.tmp,
}
);
UX_STEP_INIT(
ux_712_step_dummy,
NULL,
NULL,
{
ui_712_next_field();
}
);
UX_STEP_CB(
ux_712_step_approve,
pb,
ui_712_approve(NULL),
{
&C_icon_validate_14,
"Approve",
});
UX_STEP_CB(
ux_712_step_reject,
pb,
ui_712_reject(NULL),
{
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_712_flow,
&ux_712_step_review,
&ux_712_step_dynamic,
&ux_712_step_dummy,
&ux_712_step_approve,
&ux_712_step_reject);
#endif // HAVE_EIP712_FULL_SUPPORT

View File

@@ -1,12 +0,0 @@
#ifndef UI_FLOW_712_H_
#define UI_FLOW_712_H_
#ifdef HAVE_EIP712_FULL_SUPPORT
#include "ux_flow_engine.h"
extern const ux_flow_step_t* const ux_712_flow[];
#endif // HAVE_EIP712_FULL_SUPPORT
#endif // UI_FLOW_712_H_

View File

@@ -1,72 +1,87 @@
#include "shared_context.h"
#include "ui_callbacks.h"
#include "common_712.h"
#include "ethUtils.h"
#ifdef HAVE_EIP712_FULL_SUPPORT
void prepare_domain_hash_v0() {
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
KECCAK256_HASH_BYTESIZE,
tmpCtx.messageSigningContext712.domainHash);
}
#include "ui_logic.h"
#include "shared_context.h" // strings
void prepare_message_hash_v0() {
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
KECCAK256_HASH_BYTESIZE,
tmpCtx.messageSigningContext712.messageHash);
enum { UI_712_POS_REVIEW, UI_712_POS_END };
static uint8_t ui_pos;
static void dummy_cb(void) {
if (!ui_712_next_field()) {
if (ui_pos == UI_712_POS_REVIEW) {
ux_flow_next();
ui_pos = UI_712_POS_END;
} else // UI_712_POS_END
{
ux_flow_prev();
ui_pos = UI_712_POS_REVIEW;
}
}
}
// clang-format off
UX_STEP_NOCB(
ux_sign_712_v0_flow_1_step,
ux_712_step_review,
pnn,
{
&C_icon_certificate,
"Sign",
&C_icon_eye,
"Review",
"typed message",
});
UX_STEP_NOCB_INIT(
ux_sign_712_v0_flow_2_step,
bnnn_paging,
prepare_domain_hash_v0(),
{
.title = "Domain hash",
UX_STEP_NOCB(
ux_712_step_dynamic,
bnnn_paging,
{
.title = strings.tmp.tmp2,
.text = strings.tmp.tmp,
});
UX_STEP_NOCB_INIT(
ux_sign_712_v0_flow_3_step,
bnnn_paging,
prepare_message_hash_v0(),
{
.title = "Message hash",
.text = strings.tmp.tmp,
});
}
);
UX_STEP_INIT(
ux_712_step_dummy,
NULL,
NULL,
{
dummy_cb();
}
);
UX_STEP_CB(
ux_sign_712_v0_flow_4_step,
pbb,
ui_712_approve_cb(NULL),
ux_712_step_approve,
pb,
ui_712_approve(NULL),
{
&C_icon_validate_14,
"Sign",
"message",
"Approve",
});
UX_STEP_CB(
ux_sign_712_v0_flow_5_step,
pbb,
ui_712_reject_cb(NULL),
ux_712_step_reject,
pb,
ui_712_reject(NULL),
{
&C_icon_crossmark,
"Cancel",
"signature",
"Reject",
});
// clang-format on
UX_FLOW(ux_sign_712_v0_flow,
&ux_sign_712_v0_flow_1_step,
&ux_sign_712_v0_flow_2_step,
&ux_sign_712_v0_flow_3_step,
&ux_sign_712_v0_flow_4_step,
&ux_sign_712_v0_flow_5_step);
UX_FLOW(ux_712_flow,
&ux_712_step_review,
&ux_712_step_dynamic,
&ux_712_step_dummy,
&ux_712_step_approve,
&ux_712_step_reject);
void ui_712_start(void) {
ux_flow_init(0, ux_712_flow, NULL);
ui_pos = UI_712_POS_REVIEW;
}
void ui_712_switch_to_message(void) {
ux_flow_init(0, ux_712_flow, &ux_712_step_dynamic);
ui_pos = UI_712_POS_REVIEW;
}
void ui_712_switch_to_sign(void) {
ux_flow_init(0, ux_712_flow, &ux_712_step_approve);
ui_pos = UI_712_POS_END;
}
#endif // HAVE_EIP712_FULL_SUPPORT

View File

@@ -0,0 +1,72 @@
#include "shared_context.h"
#include "ui_callbacks.h"
#include "common_712.h"
#include "ethUtils.h"
void prepare_domain_hash_v0() {
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
KECCAK256_HASH_BYTESIZE,
tmpCtx.messageSigningContext712.domainHash);
}
void prepare_message_hash_v0() {
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
KECCAK256_HASH_BYTESIZE,
tmpCtx.messageSigningContext712.messageHash);
}
// clang-format off
UX_STEP_NOCB(
ux_sign_712_v0_flow_1_step,
pnn,
{
&C_icon_certificate,
"Sign",
"typed message",
});
UX_STEP_NOCB_INIT(
ux_sign_712_v0_flow_2_step,
bnnn_paging,
prepare_domain_hash_v0(),
{
.title = "Domain hash",
.text = strings.tmp.tmp,
});
UX_STEP_NOCB_INIT(
ux_sign_712_v0_flow_3_step,
bnnn_paging,
prepare_message_hash_v0(),
{
.title = "Message hash",
.text = strings.tmp.tmp,
});
UX_STEP_CB(
ux_sign_712_v0_flow_4_step,
pbb,
ui_712_approve_cb(NULL),
{
&C_icon_validate_14,
"Sign",
"message",
});
UX_STEP_CB(
ux_sign_712_v0_flow_5_step,
pbb,
ui_712_reject_cb(NULL),
{
&C_icon_crossmark,
"Cancel",
"signature",
});
// clang-format on
UX_FLOW(ux_sign_712_v0_flow,
&ux_sign_712_v0_flow_1_step,
&ux_sign_712_v0_flow_2_step,
&ux_sign_712_v0_flow_3_step,
&ux_sign_712_v0_flow_4_step,
&ux_sign_712_v0_flow_5_step);

View File

@@ -6,8 +6,6 @@
#include "mem.h"
#include "mem_utils.h"
#include "os_io.h"
#include "ux_flow_engine.h"
#include "ui_flow_712.h"
#include "shared_context.h"
#include "ethUtils.h" // getEthDisplayableAddress
#include "utils.h" // uint256_to_decimal
@@ -18,6 +16,7 @@
#include "apdu_constants.h" // APDU response codes
#include "typed_data.h"
#include "commands_712.h"
#include "common_ui.h"
static t_ui_context *ui_ctx = NULL;
@@ -106,43 +105,34 @@ void ui_712_set_value(const char *const str, uint8_t length) {
void ui_712_redraw_generic_step(void) {
if (!ui_ctx->shown) // Initialize if it is not already
{
ux_flow_init(0, ux_712_flow, NULL);
ui_712_start();
ui_ctx->shown = true;
} else {
// not pretty, manually changes the internal state of the UX flow
// so that we always land on the first screen of a paging step without any visible
// screen glitching (quick screen switching)
G_ux.flow_stack[G_ux.stack_count - 1].index = 0;
// since the flow now thinks we are displaying the first step, do next
ux_flow_next();
ui_712_switch_to_message();
}
}
/**
* Called on the intermediate dummy screen between the dynamic step
* && the approve/reject screen
* Called to fetch the next field if they have not all been processed yet
*
* @return whether there will be a next field
*/
void ui_712_next_field(void) {
bool ui_712_next_field(void) {
bool next = false;
if (ui_ctx == NULL) {
apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
return;
}
if (ui_ctx->structs_to_review > 0) {
ui_712_review_struct(path_get_nth_field_to_last(ui_ctx->structs_to_review));
ui_ctx->structs_to_review -= 1;
} else {
if (ui_ctx->structs_to_review > 0) {
ui_712_review_struct(path_get_nth_field_to_last(ui_ctx->structs_to_review));
ui_ctx->structs_to_review -= 1;
}
if (!ui_ctx->end_reached) {
handle_eip712_return_code(true);
} else {
if (ui_ctx->pos == UI_712_POS_REVIEW) {
ux_flow_next();
ui_ctx->pos = UI_712_POS_END;
} else {
ux_flow_prev();
ui_ctx->pos = UI_712_POS_REVIEW;
}
next = true;
}
}
return next;
}
/**
@@ -419,7 +409,7 @@ void ui_712_end_sign(void) {
ui_ctx->end_reached = true;
if (N_storage.verbose_eip712 || (ui_ctx->filtering_mode == EIP712_FILTERING_FULL)) {
ui_712_next_field();
ui_712_switch_to_sign();
}
}
@@ -430,7 +420,6 @@ bool ui_712_init(void) {
if ((ui_ctx = MEM_ALLOC_AND_ALIGN_TYPE(*ui_ctx))) {
ui_ctx->shown = false;
ui_ctx->end_reached = false;
ui_ctx->pos = UI_712_POS_REVIEW;
ui_ctx->filtering_mode = EIP712_FILTERING_BASIC;
} else {
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;

View File

@@ -11,12 +11,9 @@
typedef enum { EIP712_FILTERING_BASIC, EIP712_FILTERING_FULL } e_eip712_filtering_mode;
typedef enum { UI_712_POS_REVIEW, UI_712_POS_END } e_ui_position;
typedef struct {
bool shown;
bool end_reached;
e_ui_position pos;
uint8_t filtering_mode;
uint8_t filters_to_process;
uint8_t field_flags;
@@ -25,7 +22,7 @@ typedef struct {
bool ui_712_init(void);
void ui_712_deinit(void);
void ui_712_next_field(void);
bool ui_712_next_field(void);
void ui_712_review_struct(const void *const struct_ptr);
bool ui_712_new_field(const void *const field_ptr, const uint8_t *const data, uint8_t length);
void ui_712_end_sign(void);