Skip to content

Commit

Permalink
Merge pull request #12 from qtumproject/time/settings
Browse files Browse the repository at this point in the history
Add settings menu
  • Loading branch information
qtum-neil authored Oct 16, 2023
2 parents d54fa5a + 7b4388d commit 71c11a1
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 12 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1
HAVE_APPLICATION_FLAG_LIBRARY = 1

# Enables direct data signing without having to specify it in the settings.
ALLOW_DATA?=0
ifneq ($(ALLOW_DATA),0)
DEFINES += HAVE_ALLOW_DATA
endif

ifeq ($(COIN),qtum_testnet)

# Qtum testnet, no legacy support
Expand Down
24 changes: 20 additions & 4 deletions src/common/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include "../crypto.h"
#endif

#define DELEGATIONS_ADDRESS "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x86"
#define ADD_DELEGATION_HASH "\x4c\x0e\x96\x8c"
#define REMOVE_DELEGATION_HASH "\x3d\x66\x6e\x8b"

size_t get_push_script_size(uint32_t n) {
if (n <= 16)
return 1; // OP_0 and OP_1 .. OP_16
Expand Down Expand Up @@ -379,6 +383,20 @@ bool is_opsender(const uint8_t script[], size_t script_len) {
return is_opcontract((uint8_t *) script, script_len, OP_SENDER);
}

bool is_delegate(const uint8_t script[], size_t script_len) {
char contractaddress[20];
size_t i;
for (i = 0; i < sizeof(contractaddress); i++) {
contractaddress[i] = script[script_len - 21 + i];
}
return strncmp(contractaddress, DELEGATIONS_ADDRESS, sizeof(contractaddress)) == 0;
}

bool is_contract_blind_sign(const uint8_t script[], size_t script_len) {
bool isContract = is_opcreate(script, script_len) || is_opcall(script, script_len);
return isContract && !is_delegate(script, script_len);
}

bool get_script_sender_address(uint8_t *buffer, size_t size, uint8_t *script) {
uint8_t *pkh = 0;
unsigned int pkhSize = 0;
Expand All @@ -395,10 +413,6 @@ bool get_sender_sig(uint8_t *buffer, size_t size, uint8_t **sig, unsigned int *s
}

#ifndef SKIP_FOR_CMOCKA
#define DELEGATIONS_ADDRESS "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x86"
#define ADD_DELEGATION_HASH "\x4c\x0e\x96\x8c"
#define REMOVE_DELEGATION_HASH "\x3d\x66\x6e\x8b"

bool opcall_addr_encode(const uint8_t script[],
size_t script_len,
char *out,
Expand Down Expand Up @@ -455,6 +469,8 @@ bool opcall_addr_encode(const uint8_t script[],
snprintf(out, out_len, "Delegate to %s (fee %d %%)", stakerbase58, delegationfee);
} else if (strncmp(functionhash, REMOVE_DELEGATION_HASH, sizeof(functionhash)) == 0) {
strncpy(out, "Undelegate", out_len);
} else {
return 0;
}
} else {
uint8_t contractaddressstring[41];
Expand Down
2 changes: 2 additions & 0 deletions src/common/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ bool is_opcall(const uint8_t script[], size_t script_len);

bool is_opsender(const uint8_t script[], size_t script_len);

bool is_contract_blind_sign(const uint8_t script[], size_t script_len);

/**
* Returns the size in bytes of the minimal push opcode for <n>, where n a uint32_t.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* Maximum scriptPubKey length for an output that we can recognize.
*/
#define MAX_OUTPUT_SCRIPTPUBKEY_LEN 400 // max 393 for contracts; other scripts are shorter
#define MAX_INPUT_SCRIPTPUBKEY_LEN 83 // max 83 for OP_RETURN; other scripts are shorter
#define MAX_INPUT_SCRIPTPUBKEY_LEN 35 // P2PK's scriptPubKeys are the longest supported

/**
* Maximum length of a wallet registered into the device (characters), excluding terminating NULL.
Expand Down
12 changes: 12 additions & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

#include "ux.h"

Expand All @@ -27,3 +28,14 @@ extern ux_state_t G_ux;
* Global structure with the parameters to exchange with the BOLOS UX application.
*/
extern bolos_ux_params_t G_ux_params;

#define N_storage (*(volatile internalStorage_t *) PIC(&N_storage_real))
typedef struct internalStorage_t {
bool dataAllowed;
bool initialized;
} internalStorage_t;

/**
* Global structure for settings storage.
*/
extern const internalStorage_t N_storage_real;
11 changes: 11 additions & 0 deletions src/handler/sign_psbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,17 @@ static bool read_outputs(dispatcher_context_t *dc,
// external output, user needs to validate
++external_outputs_count;

// check if output contract data is allowed
bool isContractBlindSign =
is_contract_blind_sign(output.in_out.scriptPubKey, output.in_out.scriptPubKey_len);
if (isContractBlindSign && !N_storage.dataAllowed) {
ui_warn_contract_data(dc);
if (!N_storage.dataAllowed) {
SEND_SW(dc, SW_SIGNATURE_FAIL);
return false;
}
}

if (!dry_run &&
!display_output(dc, st, cur_output_index, external_outputs_count, &output))
return false;
Expand Down
24 changes: 24 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ bolos_ux_params_t G_ux_params;

dispatcher_context_t G_dispatcher_context;

const internalStorage_t N_storage_real;

// clang-format off
const command_descriptor_t COMMAND_DESCRIPTORS[] = {
{
Expand Down Expand Up @@ -236,6 +238,17 @@ void coin_main() {
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // HAVE_BLE

if (!N_storage.initialized) {
internalStorage_t storage;
#ifdef HAVE_ALLOW_DATA
storage.dataAllowed = true;
#else
storage.dataAllowed = false;
#endif
storage.initialized = true;
nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
}

USB_power(0);
USB_power(1);

Expand Down Expand Up @@ -289,6 +302,17 @@ static void swap_library_main_helper(struct libargs_s *args) {
ux_stack_push();
#endif // HAVE_BAGL

if (!N_storage.initialized) {
internalStorage_t storage;
#ifdef HAVE_ALLOW_DATA
storage.dataAllowed = true;
#else
storage.dataAllowed = false;
#endif
storage.initialized = true;
nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
}

USB_power(0);
USB_power(1);
// ui_idle();
Expand Down
5 changes: 5 additions & 0 deletions src/ui/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ bool ui_warn_nondefault_sighash(dispatcher_context_t *context) {
return io_ui_process(context, true);
}

bool ui_warn_contract_data(dispatcher_context_t *context) {
ui_warning_contract_data();
return io_ui_process(context, true);
}

bool ui_transaction_prompt(dispatcher_context_t *context,
const int external_outputs_total_count,
const bool sign_sender) {
Expand Down
4 changes: 4 additions & 0 deletions src/ui/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ bool ui_warn_unverified_segwit_inputs(dispatcher_context_t *context);

bool ui_warn_nondefault_sighash(dispatcher_context_t *context);

bool ui_warn_contract_data(dispatcher_context_t *context);

bool ui_validate_output(dispatcher_context_t *context,
int index,
int total_count,
Expand Down Expand Up @@ -179,6 +181,8 @@ bool ui_post_processing_confirm_transaction(dispatcher_context_t *context, bool

bool ui_post_processing_confirm_message(dispatcher_context_t *context, bool success);

void ui_warning_contract_data(void);

#ifdef HAVE_NBGL
bool ui_transaction_prompt(dispatcher_context_t *context,
const int external_outputs_total_count,
Expand Down
25 changes: 25 additions & 0 deletions src/ui/display_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,25 @@ UX_STEP_CB(ux_sign_message_accept_new,
set_ux_flow_response(true),
{&C_icon_validate_14, "Sign", "message"});

#ifdef TARGET_NANOS
UX_STEP_CB(ux_warning_contract_data_step,
bnnn_paging,
set_ux_flow_response(false),
{
"Error",
"Blind signing must be enabled in Settings",
});
#else
UX_STEP_CB(ux_warning_contract_data_step,
pnn,
set_ux_flow_response(false),
{
&C_icon_crossmark,
"Blind signing must be",
"enabled in Settings",
});
#endif

// FLOW to display BIP32 path and a message hash to sign:
// #1 screen: certificate icon + "Sign message"
// #2 screen: display BIP32 Path
Expand Down Expand Up @@ -424,6 +443,8 @@ UX_FLOW(ux_sign_sender_transaction_flow,
&ux_sign_sender_step,
&ux_display_reject_step);

UX_FLOW(ux_warning_contract_data_flow, &ux_warning_contract_data_step);

void ui_display_pubkey_flow(void) {
ux_flow_init(0, ux_display_pubkey_flow, NULL);
}
Expand Down Expand Up @@ -492,4 +513,8 @@ void ui_accept_transaction_flow(bool is_self_transfer, bool sign_sender) {
}
}

void ui_warning_contract_data(void) {
ux_flow_init(0, ux_warning_contract_data_flow, NULL);
}

#endif // HAVE_BAGL
17 changes: 17 additions & 0 deletions src/ui/display_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,4 +549,21 @@ void ui_display_post_processing_confirm_wallet_spend(bool success) {
}
}

static void ui_warning_contract_data_choice(bool confirm) {
if (confirm) {
ux_flow_response_false();
} else {
ui_menu_settings();
}
}

void ui_warning_contract_data(void) {
nbgl_useCaseChoice(&C_round_warning_64px,
"This message cannot\nbe clear-signed",
"Enable blind-signing in\nthe settings to sign\nthis transaction.",
"Exit",
"Go to settings",
ui_warning_contract_data_choice);
}

#endif // HAVE_NBGL
5 changes: 5 additions & 0 deletions src/ui/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ void ui_menu_main_flow_bitcoin(void);
* Show main menu for Testnet (ready screen, version, about, quit).
*/
void ui_menu_main_flow_bitcoin_testnet(void);

/**
* Show settings submenu
*/
void ui_menu_settings(void);
58 changes: 58 additions & 0 deletions src/ui/menu_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include "../globals.h"
#include "menu.h"

static void display_settings(const ux_flow_step_t* const start_step);
static void switch_settings_blind_signing(void);

// We have a screen with the icon and "Bitcoin is ready" for Bitcoin,
// "Bitcoin Testnet is ready" for Bitcoin Testnet.
UX_STEP_NOCB(ux_menu_ready_step_bitcoin, pnn, {&C_bitcoin_logo, "Qtum", "is ready"});
Expand All @@ -31,6 +34,7 @@ UX_STEP_NOCB(ux_menu_ready_step_bitcoin_testnet,

UX_STEP_NOCB(ux_menu_version_step, bn, {"Version", APPVERSION});
UX_STEP_CB(ux_menu_about_step, pb, ui_menu_about(), {&C_icon_certificate, "About"});
UX_STEP_CB(ux_menu_settings_step, pb, ui_menu_settings(), {&C_icon_eye, "Settings"});
UX_STEP_VALID(ux_menu_exit_step, pb, os_sched_exit(-1), {&C_icon_dashboard_x, "Quit"});

// FLOW for the main menu (for bitcoin):
Expand All @@ -42,6 +46,7 @@ UX_FLOW(ux_menu_main_flow_bitcoin,
&ux_menu_ready_step_bitcoin,
&ux_menu_version_step,
&ux_menu_about_step,
&ux_menu_settings_step,
&ux_menu_exit_step,
FLOW_LOOP);

Expand All @@ -54,6 +59,7 @@ UX_FLOW(ux_menu_main_flow_bitcoin_testnet,
&ux_menu_ready_step_bitcoin_testnet,
&ux_menu_version_step,
&ux_menu_about_step,
&ux_menu_settings_step,
&ux_menu_exit_step,
FLOW_LOOP);

Expand Down Expand Up @@ -84,4 +90,56 @@ void ui_menu_main_flow_bitcoin_testnet(void) {
void ui_menu_about(void) {
ux_flow_init(0, ux_menu_about_flow, NULL);
}

void ui_menu_settings(void) {
display_settings(NULL);
}

#define ENABLED_STR "Enabled"
#define DISABLED_STR "Disabled"
#define BUF_INCREMENT (MAX(strlen(ENABLED_STR), strlen(DISABLED_STR)) + 1)
char strings[BUF_INCREMENT];
#define SETTING_BLIND_SIGNING_STATE strings
#define BOOL_TO_STATE_STR(b) (b ? ENABLED_STR : DISABLED_STR)

// clang-format off
UX_STEP_CB(
ux_settings_flow_blind_signing_step,
#ifdef TARGET_NANOS
bnnn_paging,
#else
bnnn,
#endif
switch_settings_blind_signing(),
{
#ifdef TARGET_NANOS
.title = "Blind signing",
.text =
#else
"Blind signing",
"Transaction",
"blind signing",
#endif
SETTING_BLIND_SIGNING_STATE
});

UX_FLOW(ux_settings_flow,
&ux_settings_flow_blind_signing_step, &ux_menu_back_step, FLOW_LOOP);

static void display_settings(const ux_flow_step_t* const start_step) {
strlcpy(SETTING_BLIND_SIGNING_STATE, BOOL_TO_STATE_STR(N_storage.dataAllowed), BUF_INCREMENT);

ux_flow_init(0, ux_settings_flow, start_step);
}

static void toggle_setting(volatile bool* setting, const ux_flow_step_t* ui_step) {
bool value = !*setting;
nvm_write((void*) setting, (void*) &value, sizeof(value));
display_settings(ui_step);
}

static void switch_settings_blind_signing(void) {
toggle_setting(&N_storage.dataAllowed, &ux_settings_flow_blind_signing_step);
}

#endif // HAVE_BAGL
Loading

0 comments on commit 71c11a1

Please sign in to comment.