Alexander Kopachov 3 лет назад
Родитель
Сommit
4374e301b6

+ 11 - 2
FAQ.md

@@ -34,7 +34,7 @@ When Flipper Authenticator is running `totp` CLI is available for you to list, a
 
 **YES!**
 
-Just pick the token you would like to auto-type then hold "arrow down" button for 1-2sec. and Flipper Authenticator will type it instead of you 😀
+Just pick the token you would like to auto-type then hold <span title="Arrow Down">▼</span> button for 1-2sec. and let Flipper Authenticator type it instead of you 😀
 
 ## How to change\recover PIN?
 
@@ -49,6 +49,15 @@ To do that you may use following CLI commands:
 
 All token secrets are stored in encrypted form and are tied to an original Flipper device and PIN. Given that, there is no sense to try to backup `/ext/apps/Misc/totp.conf` file as it will not help you in situation when you loose your Flipper device. Instead use your favorite password manager to store plain token secrets and\or any other information which will help you recover your accounts.
 
+## How to reset application?
+
+There are two options to reset Flipper Authenticator to its default:
+
+1. Delete `/ext/authenticator/totp.conf` file
+2. Use `totp reset` CLI command
+
+**Regardless of which option you use, please pay attention to the fact that <ins>you will loose everything you configured and added to Flipper Authenticator application, including token secrets.</ins>**
+
 ## Flipper Authenticator generates invalid codes, why so?
 
 There are multiple reasons why Flipper Authenticator generates invalid codes:
@@ -67,4 +76,4 @@ Sometimes it is possible that you just made a mistake while typing or copying to
 
 ### Token hashing algorithm is not correct
 
-In majority of situation using default hashing algorithm `SHA1` should work just fine. But for some rare providers it might be necessary to use `SHA256` or `SHA512` as a hashinig alogorithm.
+In majority of situations using default hashing algorithm `SHA1` should work just fine. But for some rare providers it might be necessary to use `SHA256` or `SHA512` as a hashinig alogorithm.

+ 15 - 4
totp/cli/cli.c

@@ -11,6 +11,7 @@
 #include "commands/move/move.h"
 #include "commands/pin/pin.h"
 #include "commands/notification/notification.h"
+#include "commands/reset/reset.h"
 
 static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
     TOTP_CLI_PRINTF(
@@ -20,7 +21,8 @@ static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
 }
 
 static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
-    PluginState* plugin_state = (PluginState*)context;
+    TotpCliContext* cli_context = context;
+    PluginState* plugin_state = cli_context->plugin_state;
 
     FuriString* cmd = furi_string_alloc();
 
@@ -55,6 +57,8 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
         totp_cli_command_pin_handle(plugin_state, args, cli);
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_NOTIFICATION) == 0) {
         totp_cli_command_notification_handle(plugin_state, args, cli);
+    } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
+        totp_cli_command_reset_handle(cli, cli_context->event_queue);
     } else {
         totp_cli_print_unknown_command(cmd);
     }
@@ -62,15 +66,22 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
     furi_string_free(cmd);
 }
 
-void totp_cli_register_command_handler(PluginState* plugin_state) {
+TotpCliContext*
+    totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue) {
     Cli* cli = furi_record_open(RECORD_CLI);
+    TotpCliContext* context = malloc(sizeof(TotpCliContext));
+    furi_check(context != NULL);
+    context->plugin_state = plugin_state;
+    context->event_queue = event_queue;
     cli_add_command(
-        cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, plugin_state);
+        cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context);
     furi_record_close(RECORD_CLI);
+    return context;
 }
 
-void totp_cli_unregister_command_handler() {
+void totp_cli_unregister_command_handler(TotpCliContext* context) {
     Cli* cli = furi_record_open(RECORD_CLI);
     cli_delete_command(cli, TOTP_CLI_COMMAND_NAME);
     furi_record_close(RECORD_CLI);
+    free(context);
 }

+ 8 - 2
totp/cli/cli.h

@@ -3,5 +3,11 @@
 #include <cli/cli.h>
 #include "../types/plugin_state.h"
 
-void totp_cli_register_command_handler(PluginState* plugin_state);
-void totp_cli_unregister_command_handler();
+typedef struct {
+    PluginState* plugin_state;
+    FuriMessageQueue* event_queue;
+} TotpCliContext;
+
+TotpCliContext*
+    totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue);
+void totp_cli_unregister_command_handler(TotpCliContext* context);

+ 41 - 0
totp/cli/cli_helpers.c

@@ -1,5 +1,6 @@
 #include "cli_helpers.h"
 #include <cli/cli.h>
+#include "../types/plugin_event.h"
 
 bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) {
     if(plugin_state->current_scene == TotpSceneAuthentication) {
@@ -17,5 +18,45 @@ bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) {
         }
     }
 
+    return true;
+}
+
+void totp_cli_force_close_app(FuriMessageQueue* event_queue) {
+    PluginEvent event = {.type = EventForceCloseApp};
+    furi_message_queue_put(event_queue, &event, FuriWaitForever);
+}
+
+bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input) {
+    uint8_t c;
+    while(cli_read(cli, &c, 1) == 1) {
+        if(c == CliSymbolAsciiEsc) {
+            // Some keys generating escape-sequences
+            // We need to ignore them as we care about alpha-numerics only
+            uint8_t c2;
+            cli_read_timeout(cli, &c2, 1, 0);
+            cli_read_timeout(cli, &c2, 1, 0);
+        } else if(c == CliSymbolAsciiETX) {
+            cli_nl();
+            return false;
+        } else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+            if(mask_user_input) {
+                putc('*', stdout);
+            } else {
+                putc(c, stdout);
+            }
+            fflush(stdout);
+            furi_string_push_back(out_str, c);
+        } else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
+            size_t out_str_size = furi_string_size(out_str);
+            if(out_str_size > 0) {
+                TOTP_CLI_DELETE_LAST_CHAR();
+                furi_string_left(out_str, out_str_size - 1);
+            }
+        } else if(c == CliSymbolAsciiCR) {
+            cli_nl();
+            break;
+        }
+    }
+
     return true;
 }

+ 16 - 1
totp/cli/cli_helpers.h

@@ -45,7 +45,22 @@
  * @brief Checks whether user is authenticated and entered correct PIN.
  *        If user is not authenticated it prompts user to enter correct PIN to authenticate.
  * @param plugin_state application state
- * @param cli reference to the firmware CLI subsystem 
+ * @param cli pointer to the firmware CLI subsystem 
  * @return \c true if user is already authenticated or successfully authenticated; \c false otherwise
  */
 bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli);
+
+/**
+ * @brief Forces application to be instantly closed
+ * @param event_queue main app queue
+ */
+void totp_cli_force_close_app(FuriMessageQueue* event_queue);
+
+/**
+ * @brief Reads line of characters from console
+ * @param cli pointer to the firmware CLI subsystem 
+ * @param out_str pointer to an output string to put read line to
+ * @param mask_user_input whether to mask input characters in console or not
+ * @return \c true if line successfully read and confirmed; \c false otherwise
+ */
+bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input);

+ 5 - 38
totp/cli/commands/add/add.c

@@ -76,43 +76,6 @@ static void furi_string_secure_free(FuriString* str) {
     furi_string_free(str);
 }
 
-static bool totp_cli_read_secret(Cli* cli, FuriString* out_str, bool mask_user_input) {
-    uint8_t c;
-    while(cli_read(cli, &c, 1) == 1) {
-        if(c == CliSymbolAsciiEsc) {
-            // Some keys generating escape-sequences
-            // We need to ignore them as we care about alpha-numerics only
-            uint8_t c2;
-            cli_read_timeout(cli, &c2, 1, 0);
-            cli_read_timeout(cli, &c2, 1, 0);
-        } else if(c == CliSymbolAsciiETX) {
-            TOTP_CLI_DELETE_CURRENT_LINE();
-            TOTP_CLI_PRINTF("Cancelled by user\r\n");
-            return false;
-        } else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
-            if(mask_user_input) {
-                putc('*', stdout);
-            } else {
-                putc(c, stdout);
-            }
-            fflush(stdout);
-            furi_string_push_back(out_str, c);
-        } else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
-            size_t out_str_size = furi_string_size(out_str);
-            if(out_str_size > 0) {
-                TOTP_CLI_DELETE_LAST_CHAR();
-                furi_string_left(out_str, out_str_size - 1);
-            }
-        } else if(c == CliSymbolAsciiCR) {
-            cli_nl();
-            break;
-        }
-    }
-
-    TOTP_CLI_DELETE_LAST_LINE();
-    return true;
-}
-
 void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
     FuriString* temp_str = furi_string_alloc();
     TokenInfo* token_info = token_info_alloc();
@@ -178,13 +141,17 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
     // Reading token secret
     furi_string_reset(temp_str);
     TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
-    if(!totp_cli_read_secret(cli, temp_str, mask_user_input) ||
+    if(!totp_cli_read_line(cli, temp_str, mask_user_input) ||
        !totp_cli_ensure_authenticated(plugin_state, cli)) {
+        TOTP_CLI_DELETE_LAST_LINE();
+        TOTP_CLI_PRINTF("Cancelled by user\r\n");
         furi_string_secure_free(temp_str);
         token_info_free(token_info);
         return;
     }
 
+    TOTP_CLI_DELETE_LAST_LINE();
+
     if(!token_info_set_secret(
            token_info,
            furi_string_get_cstr(temp_str),

+ 3 - 0
totp/cli/commands/help/help.c

@@ -7,6 +7,7 @@
 #include "../move/move.h"
 #include "../pin/pin.h"
 #include "../notification/notification.h"
+#include "../reset/reset.h"
 
 void totp_cli_command_help_docopt_commands() {
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
@@ -29,6 +30,7 @@ void totp_cli_command_help_handle() {
     totp_cli_command_move_docopt_usage();
     totp_cli_command_pin_docopt_usage();
     totp_cli_command_notification_docopt_usage();
+    totp_cli_command_reset_docopt_usage();
     cli_nl();
     TOTP_CLI_PRINTF("Commands:\r\n");
     totp_cli_command_help_docopt_commands();
@@ -39,6 +41,7 @@ void totp_cli_command_help_handle() {
     totp_cli_command_move_docopt_commands();
     totp_cli_command_pin_docopt_commands();
     totp_cli_command_notification_docopt_commands();
+    totp_cli_command_reset_docopt_commands();
     cli_nl();
     TOTP_CLI_PRINTF("Arguments:\r\n");
     totp_cli_command_add_docopt_arguments();

+ 37 - 0
totp/cli/commands/reset/reset.c

@@ -0,0 +1,37 @@
+#include "reset.h"
+
+#include <stdlib.h>
+#include <furi/furi.h>
+#include "../../cli_helpers.h"
+#include "../../../services/config/config.h"
+
+#define TOTP_CLI_RESET_CONFIRMATION_KEYWORD "YES"
+
+void totp_cli_command_reset_docopt_commands() {
+    TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_RESET
+                    "            Reset application to default settings\r\n");
+}
+
+void totp_cli_command_reset_docopt_usage() {
+    TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_RESET "\r\n");
+}
+
+void totp_cli_command_reset_handle(Cli* cli, FuriMessageQueue* event_queue) {
+    TOTP_CLI_PRINTF(
+        "As a result of reset all the settings and tokens will be permanently lost.\r\n");
+    TOTP_CLI_PRINTF("Do you really want to reset application?\r\n");
+    TOTP_CLI_PRINTF("Type \"" TOTP_CLI_RESET_CONFIRMATION_KEYWORD
+                    "\" and hit <ENTER> to confirm:\r\n");
+    FuriString* temp_str = furi_string_alloc();
+    bool is_confirmed = totp_cli_read_line(cli, temp_str, false) &&
+                        furi_string_cmpi_str(temp_str, TOTP_CLI_RESET_CONFIRMATION_KEYWORD) == 0;
+    furi_string_free(temp_str);
+    if(is_confirmed) {
+        totp_config_file_reset();
+        TOTP_CLI_PRINTF("Application has been successfully reset to default.\r\n");
+        TOTP_CLI_PRINTF("Now application will be closed to apply all the changes.\r\n");
+        totp_cli_force_close_app(event_queue);
+    } else {
+        TOTP_CLI_PRINTF("Action was not confirmed by user\r\n");
+    }
+}

+ 10 - 0
totp/cli/commands/reset/reset.h

@@ -0,0 +1,10 @@
+#pragma once
+
+#include <cli/cli.h>
+#include "../../../types/plugin_state.h"
+
+#define TOTP_CLI_COMMAND_RESET "reset"
+
+void totp_cli_command_reset_handle(Cli* cli, FuriMessageQueue* event_queue);
+void totp_cli_command_reset_docopt_commands();
+void totp_cli_command_reset_docopt_usage();

+ 6 - 0
totp/services/config/config.c

@@ -730,4 +730,10 @@ TotpConfigFileUpdateResult
 
     totp_close_storage();
     return update_result;
+}
+
+void totp_config_file_reset() {
+    Storage* storage = totp_open_storage();
+    storage_simply_remove(storage, CONFIG_FILE_PATH);
+    totp_close_storage();
 }

+ 6 - 1
totp/services/config/config.h

@@ -116,4 +116,9 @@ TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginSta
  * @return Config file update result
  */
 TotpConfigFileUpdateResult
-    totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
+    totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
+
+/**
+ * @brief Reset all the settings to default
+ */
+void totp_config_file_reset();

+ 7 - 3
totp/totp_app.c

@@ -143,7 +143,7 @@ int32_t totp_app() {
         return 255;
     }
 
-    totp_cli_register_command_handler(plugin_state);
+    TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state, event_queue);
     totp_scene_director_init_scenes(plugin_state);
     if(!totp_activate_initial_scene(plugin_state)) {
         FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
@@ -172,7 +172,11 @@ int32_t totp_app() {
                 last_user_interaction_time = furi_get_tick();
             }
 
-            processing = totp_scene_director_handle_event(&event, plugin_state_m);
+            if(event.type == EventForceCloseApp) {
+                processing = false;
+            } else {
+                processing = totp_scene_director_handle_event(&event, plugin_state_m);
+            }
         } else if(
             plugin_state_m->pin_set && plugin_state_m->current_scene != TotpSceneAuthentication &&
             furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
@@ -183,7 +187,7 @@ int32_t totp_app() {
         release_mutex(&state_mutex, plugin_state_m);
     }
 
-    totp_cli_unregister_command_handler();
+    totp_cli_unregister_command_handler(cli_context);
     totp_scene_director_deactivate_active_scene(plugin_state);
     totp_scene_director_dispose(plugin_state);
 

+ 1 - 4
totp/types/event_type.h

@@ -3,7 +3,4 @@
 
 typedef uint8_t EventType;
 
-enum EventTypes {
-    EventTypeTick,
-    EventTypeKey,
-};
+enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp };