diff --git a/components/gui/gui.cpp b/components/gui/gui.cpp index ec15160..789cfcb 100644 --- a/components/gui/gui.cpp +++ b/components/gui/gui.cpp @@ -21,6 +21,9 @@ #define BASE_NETWORKS_SCREEN 6 #define BASE_XPUBS_SCREEN 7 #define BASE_PSBT_CONFIRMATION 8 +#define BASE_RECKLESS 9 + +#define BACK_TO_MAIN 0xFF using std::string; @@ -53,6 +56,8 @@ static void gui_styles_create(){ title_style.text.font = &lv_font_roboto_28; } static void cb(lv_obj_t * obj, lv_event_t event); +static void back_to_main(void * ptr); +static void back_to_init(void * ptr); int gui_get_action(){ return action; @@ -206,6 +211,9 @@ static void process_init_screen(int val){ case 2: show_recovery_screen(); break; + case 3: + action = GUI_LOAD_MNEMONIC; + break; } } @@ -276,6 +284,34 @@ static void show_xpubs_screen(){ lv_obj_set_user_data(obj, 3); } +static void show_reckless_screen(){ + base = BASE_RECKLESS; + + lv_obj_clean(scr); + lv_obj_t * obj; + + obj = gui_title_create(scr, "Careful with that!"); + + uint16_t y = 100; + obj = gui_button_create(scr, "Save recovery phrase", cb); + lv_obj_set_y(obj, y); + lv_obj_set_user_data(obj, 1); + y+=100; + + obj = gui_button_create(scr, "Delete recovery phrase", cb); + lv_obj_set_y(obj, y); + lv_obj_set_user_data(obj, 2); + y+=100; + + obj = gui_button_create(scr, "Show recovery phrase", cb); + lv_obj_set_y(obj, y); + lv_obj_set_user_data(obj, 3); + y+=100; + + obj = gui_button_create(scr, "Back to main screen", cb); + lv_obj_set_user_data(obj, BACK_TO_MAIN); +} + static void process_main_screen(int val){ switch(val){ case 2: // master keys @@ -295,6 +331,9 @@ static void process_main_screen(int val){ case 6: // pick network show_networks_screen(); break; + case 7: + show_reckless_screen(); + break; } } @@ -308,7 +347,25 @@ static int copy_string(){ } static void process_command(int val){ + if(val == BACK_TO_MAIN){ + lv_async_call(back_to_main, NULL); + memset(input_buffer, 0, sizeof(input_buffer)); + return; + } switch(base){ + case BASE_RECKLESS: + switch(val){ + case 1: + action = GUI_SAVE_MNEMONIC; + break; + case 2: + action = GUI_DELETE_MNEMONIC; + break; + case 3: + action = GUI_SHOW_MNEMONIC; + break; + } + break; case BASE_INIT_SCREEN: process_init_screen(val); break; @@ -430,19 +487,36 @@ void gui_show_init_screen(){ lv_obj_t * obj; obj = gui_title_create(scr, "What do you want to do?"); + uint16_t y = 100; obj = gui_button_create(scr, "Generate new key", cb); - lv_obj_set_y(obj, 200); + lv_obj_set_y(obj, y); lv_obj_set_user_data(obj, 1); + y+=100; obj = gui_button_create(scr, "Enter recovery phrase", cb); - lv_obj_set_y(obj, 300); + lv_obj_set_y(obj, y); lv_obj_set_user_data(obj, 2); + y+=100; + + obj = gui_button_create(scr, "Load key from memory", cb); + lv_obj_set_y(obj, y); + lv_obj_set_user_data(obj, 3); + y+=100; } /********************** mnemonic screen ********************/ static lv_obj_t * tbl; +void gui_show_reckless_mnemonic(const char * mnemonic){ + + gui_alert_create("Your recovery phrase", "", "Ok"); + + lv_obj_t * alert_scr = lv_disp_get_scr_act(NULL); + + lv_obj_t * obj = gui_mnemonic_table_create(alert_scr, mnemonic); +} + void gui_show_mnemonic(const char * mnemonic){ base = BASE_MNEMONIC_SCREEN; value = 12; @@ -485,10 +559,6 @@ static const char * keymap[] = {"Q","W","E","R","T","Y","U","I","O","P","\n", "Z","X","C","V","B","N","M","<","\n", "Back","Next word","Done",""}; -static void back_to_init(void * ptr){ - gui_show_init_screen(); -} - static void cb_keyboard(lv_obj_t * obj, lv_event_t event){ if(event == LV_EVENT_RELEASED){ const char * txt = lv_btnm_get_active_btn_text(obj); @@ -652,6 +722,10 @@ void gui_show_main_screen(){ lv_obj_set_y(obj, y); lv_obj_set_user_data(obj, 6); y+=100; + obj = gui_button_create(scr, "# Reckless", cb); + lv_obj_set_y(obj, y); + lv_obj_set_user_data(obj, 7); + y+=100; // TODO: add GUI_SECURE_SHUTDOWN // TODO: add Advanced menu: @@ -659,6 +733,14 @@ void gui_show_main_screen(){ // - SD card support } +static void back_to_main(void * ptr){ + gui_show_main_screen(); +} + +static void back_to_init(void * ptr){ + gui_show_init_screen(); +} + void gui_set_default_xpubs(const char * single, const char * multisig){ default_xpubs[0] = single; default_xpubs[1] = multisig; diff --git a/components/gui/gui.h b/components/gui/gui.h index e6785ec..dc3b1e6 100644 --- a/components/gui/gui.h +++ b/components/gui/gui.h @@ -2,6 +2,7 @@ #define __GUI_H__ #include +#include "./alert/alert.h" /** possible GUI actions (main needs to handle them) */ #define GUI_NO_ACTION 0 @@ -15,6 +16,11 @@ #define GUI_VERIFY_ADDRESS 8 #define GUI_SIGN_PSBT 9 #define GUI_PSBT_CONFIRMED 10 +// reckless +#define GUI_SHOW_MNEMONIC 11 +#define GUI_SAVE_MNEMONIC 12 +#define GUI_DELETE_MNEMONIC 13 +#define GUI_LOAD_MNEMONIC 14 /** structure to display output */ typedef struct _txout_t { @@ -44,6 +50,7 @@ void gui_show_xpub(const char * fingerprint, const char * derivation, const char void gui_show_addresses(const char * derivation, const char * segwit_addr, const char * base58_addr); void gui_show_psbt(uint64_t out_amount, uint64_t change_amount, uint64_t fee, uint8_t num_outputs, txout_t * outputs); void gui_show_signed_psbt(const char * output); +void gui_show_reckless_mnemonic(const char * mnemonic); void gui_calibrate(); diff --git a/components/storage/storage.cpp b/components/storage/storage.cpp index f605a81..ff02eff 100644 --- a/components/storage/storage.cpp +++ b/components/storage/storage.cpp @@ -16,6 +16,51 @@ int storage_erase(){ // return fs.remove("/internal/gui/calibration"); } +int storage_init(){ + int err = fs.mount(&bd); + printf("%s\r\n", (err ? "Fail :(" : "OK")); + if (err) { + printf("No filesystem found, formatting...\r\n"); + err = fs.reformat(&bd); + printf("%s\r\n", (err ? "Fail :(" : "OK")); + if (err) { + printf("error: %s (%d)\r\n", strerror(-err), err); + return err; + } + } + return STORAGE_OK; +} + +int storage_save_mnemonic(const char * mnemonic){ + FILE *f = fopen("/internal/mnemonic", "w"); + if(!f){ + return -1; + } + fprintf(f, mnemonic); + fclose(f); + return 0; +} + +int storage_load_mnemonic(char ** mnemonic){ + FILE *f = fopen("/internal/mnemonic", "r"); + if(!f){ + return -1; + } + // TODO: check length + char content[300]; + fscanf(f,"%[^\n]", content); + *mnemonic = (char *)malloc(strlen(content)+1); + strcpy(*mnemonic, content); + memset(content, 0, sizeof(content)); + fclose(f); + return 0; +} + +int storage_delete_mnemonic(){ + return remove("/internal/mnemonic"); +} + +#if 0 void listRoot(){ // Display the root directory printf("Opening the root directory... "); @@ -43,21 +88,6 @@ void listRoot(){ } } -int storage_init(){ - int err = fs.mount(&bd); - printf("%s\r\n", (err ? "Fail :(" : "OK")); - if (err) { - printf("No filesystem found, formatting...\r\n"); - err = fs.reformat(&bd); - printf("%s\r\n", (err ? "Fail :(" : "OK")); - if (err) { - printf("error: %s (%d)\r\n", strerror(-err), err); - return err; - } - } - return STORAGE_OK; -} - int save(const char * fname, const char * content){ printf("Opening \"%s\"... ", fname); char * fullname = (char *)calloc(strlen(fname)+5, sizeof(char)); @@ -94,7 +124,7 @@ int makeDir(const char * dirname){ free(fullname); return err; } -#if 0 + static int qspi_init(){ int err = fs.mount(&bd); printf("%s\r\n", (err ? "Fail :(" : "OK")); diff --git a/components/storage/storage.h b/components/storage/storage.h index ac4083f..2a30ab0 100644 --- a/components/storage/storage.h +++ b/components/storage/storage.h @@ -5,6 +5,12 @@ int storage_init(); int storage_erase(); + +// reckless storage +int storage_save_mnemonic(const char * mnemonic); +int storage_load_mnemonic(char ** mnemonic); +int storage_delete_mnemonic(); + // void listRoot(); // int save(const char * fname, const char * content); // bool dirExists(const char * dirname); diff --git a/main.cpp b/main.cpp index 386d93a..6bb0d3e 100644 --- a/main.cpp +++ b/main.cpp @@ -283,6 +283,50 @@ void process_action(int action){ gui_show_init_screen(); break; } + case GUI_SHOW_MNEMONIC: + { + gui_show_reckless_mnemonic(mnemonic); + break; + } + case GUI_SAVE_MNEMONIC: + { // TODO: set and verify pin code + int res = storage_save_mnemonic(mnemonic); + if(res < 0){ + show_err("Failed to save mnemonic"); + }else{ + gui_alert_create("Success!", "Your recovery phrase is saved to memory", "Ok"); + } + break; + } + case GUI_DELETE_MNEMONIC: + { // TODO: securely erase this file + int res = storage_delete_mnemonic(); + if(res < 0){ + show_err("Failed to delete mnemonic"); + }else{ + gui_alert_create("Success!", "Your recovery phrase is removed from memory", "Ok"); + } + break; + } + case GUI_LOAD_MNEMONIC: + { + if(mnemonic != NULL){ + wally_free_string(mnemonic); + mnemonic = NULL; + } + int res = storage_load_mnemonic(&mnemonic); + if(res < 0){ + show_err("Failed to load mnemonic"); + }else{ + if(bip39_mnemonic_validate(NULL, mnemonic)!=WALLY_OK){ + show_err("mnemonic is not correct"); + }else{ + logit("main", "mnemonic is saved in memory"); + gui_get_password(); + } + } + break; + } default: show_err("unrecognized action"); } diff --git a/specter_config.h b/specter_config.h index ea2230e..89ca80a 100644 --- a/specter_config.h +++ b/specter_config.h @@ -6,9 +6,4 @@ // buffer size for host module #define SPECTER_HOST_INPUT_SIZE 3000 -/** put in debug.h your hardcoded debug mnemonic */ -// #include "debug.h" -/** or put it here and uncomment this line */ -// #define DEBUG_MNEMONIC "also panda decline code guard palace spread squirrel stereo sudden fee noodle" - #endif // __SPECTER_CONFIG_H__ \ No newline at end of file