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

+ 3 - 0
cli/cli_helpers.h

@@ -38,6 +38,9 @@
     TOTP_CLI_PRINTF(                       \
         "Invalid command arguments. use \"help\" command to get list of available commands")
 
+#define TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE() \
+    TOTP_CLI_PRINTF("An error has occurred during updating config file\r\n")
+
 /**
  * @brief Checks whether user is authenticated and entered correct PIN.
  *        If user is not authenticated it prompts user to enter correct PIN to authenticate.

+ 5 - 3
cli/commands/add/add.c

@@ -206,11 +206,13 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
 
     TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, token_info, furi_check);
     plugin_state->tokens_count++;
-    totp_config_file_save_new_token(token_info);
+    if(totp_config_file_save_new_token(token_info) == TotpConfigFileUpdateSuccess) {
+        TOTP_CLI_PRINTF("Token \"%s\" has been successfully added\r\n", token_info->name);
+    } else {
+        TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+    }
 
     if(load_generate_token_scene) {
         totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
     }
-
-    TOTP_CLI_PRINTF("Token \"%s\" has been successfully added\r\n", token_info->name);
 }

+ 7 - 4
cli/commands/delete/delete.c

@@ -93,14 +93,17 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
         plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node);
         plugin_state->tokens_count--;
 
-        totp_full_save_config_file(plugin_state);
+        if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
+            TOTP_CLI_PRINTF("Token \"%s\" has been successfully deleted\r\n", token_info->name);
+        } else {
+            TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+        }
+
+        token_info_free(token_info);
 
         if(activate_generate_token_scene) {
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
         }
-
-        TOTP_CLI_PRINTF("Token \"%s\" has been successfully deleted\r\n", token_info->name);
-        token_info_free(token_info);
     } else {
         TOTP_CLI_PRINTF("User not confirmed\r\n");
     }

+ 7 - 7
cli/commands/move/move.c

@@ -147,18 +147,18 @@ void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, C
     }
 
     if(token_updated) {
-        totp_full_save_config_file(plugin_state);
+        if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
+            TOTP_CLI_PRINTF("Token \"%s\" has been successfully updated\r\n", token_info->name);
+        } else {
+            TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+        }
+    } else {
+        TOTP_CLI_PRINT_INVALID_ARGUMENTS();
     }
 
     if(activate_generate_token_scene) {
         totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
     }
 
-    if(token_updated) {
-        TOTP_CLI_PRINTF("Token \"%s\" has been successfully updated\r\n", token_info->name);
-    } else {
-        TOTP_CLI_PRINT_INVALID_ARGUMENTS();
-    }
-
     furi_string_free(temp_str);
 }

+ 8 - 5
cli/commands/notification/notification.c

@@ -86,15 +86,18 @@ void totp_cli_command_notification_handle(PluginState* plugin_state, FuriString*
             }
 
             plugin_state->notification_method = new_method;
-            totp_config_file_update_notification_method(new_method);
+            if(totp_config_file_update_notification_method(new_method) ==
+               TotpConfigFileUpdateSuccess) {
+                TOTP_CLI_PRINTF("Notification method is set to ");
+                totp_cli_command_notification_print_method(new_method);
+                cli_nl();
+            } else {
+                TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+            }
 
             if(previous_scene != TotpSceneNone) {
                 totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
             }
-
-            TOTP_CLI_PRINTF("Notification method is set to ");
-            totp_cli_command_notification_print_method(new_method);
-            cli_nl();
         } else {
             TOTP_CLI_PRINTF("Current notification method is ");
             totp_cli_command_notification_print_method(plugin_state->notification_method);

+ 17 - 8
cli/commands/pin/pin.c

@@ -134,8 +134,14 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
                 plugin_state->crypto_verify_data = NULL;
             }
 
-            totp_crypto_seed_iv(
-                plugin_state, new_pin_length > 0 ? &new_pin[0] : NULL, new_pin_length);
+            if(!totp_crypto_seed_iv(
+                   plugin_state, new_pin_length > 0 ? &new_pin[0] : NULL, new_pin_length)) {
+                memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
+                TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+                break;
+            }
+
+            memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
 
             TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
                 TokenInfo* token_info = node->data;
@@ -152,15 +158,18 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
                 free(plain_token);
             });
 
-            totp_full_save_config_file(plugin_state);
-
             TOTP_CLI_DELETE_LAST_LINE();
 
-            if(do_change) {
-                TOTP_CLI_PRINTF("PIN has been successfully changed\r\n");
-            } else if(do_remove) {
-                TOTP_CLI_PRINTF("PIN has been successfully removed\r\n");
+            if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
+                if(do_change) {
+                    TOTP_CLI_PRINTF("PIN has been successfully changed\r\n");
+                } else if(do_remove) {
+                    TOTP_CLI_PRINTF("PIN has been successfully removed\r\n");
+                }
+            } else {
+                TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
             }
+
         } while(false);
 
         if(load_generate_token_scene) {

+ 5 - 2
cli/commands/timezone/timezone.c

@@ -33,8 +33,11 @@ void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* arg
         float tz = strtof(furi_string_get_cstr(temp_str), NULL);
         if(tz >= -12.75f && tz <= 12.75f) {
             plugin_state->timezone_offset = tz;
-            totp_config_file_update_timezone_offset(tz);
-            TOTP_CLI_PRINTF("Timezone is set to %f\r\n", tz);
+            if(totp_config_file_update_timezone_offset(tz) == TotpConfigFileUpdateSuccess) {
+                TOTP_CLI_PRINTF("Timezone is set to %f\r\n", tz);
+            } else {
+                TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
+            }
             if(plugin_state->current_scene == TotpSceneGenerateToken) {
                 totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
                 totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);

+ 405 - 157
services/config/config.c

@@ -9,6 +9,8 @@
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
 #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
 #define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
+#define CONFIG_FILE_TEMP_PATH CONFIG_FILE_PATH ".tmp"
+#define CONFIG_FILE_ORIG_PATH CONFIG_FILE_PATH ".orig"
 #define CONFIG_FILE_PATH_PREVIOUS EXT_PATH("apps/Misc") "/totp.conf"
 
 static char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
@@ -36,15 +38,38 @@ static void token_info_set_algo_from_str(TokenInfo* token_info, const FuriString
     }
 }
 
-Storage* totp_open_storage() {
+/**
+ * @brief Opens storage record
+ * @return Storage record
+ */
+static Storage* totp_open_storage() {
     return furi_record_open(RECORD_STORAGE);
 }
 
-void totp_close_storage() {
+/**
+ * @brief Closes storage record
+ */
+static void totp_close_storage() {
     furi_record_close(RECORD_STORAGE);
 }
 
-FlipperFormat* totp_open_config_file(Storage* storage) {
+/**
+ * @brief Closes config file
+ * @param file config file reference
+ */
+static void totp_close_config_file(FlipperFormat* file) {
+    if(file == NULL) return;
+    flipper_format_file_close(file);
+    flipper_format_free(file);
+}
+
+/**
+ * @brief Opens or creates TOTP application standard config file
+ * @param storage storage record to use
+ * @param[out] file opened config file
+ * @return Config file open result
+ */
+static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperFormat** file) {
     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
 
     if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) {
@@ -52,7 +77,7 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
         if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) {
             FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH);
             totp_close_config_file(fff_data_file);
-            return NULL;
+            return TotpConfigFileOpenError;
         }
     } else if(storage_common_stat(storage, CONFIG_FILE_PATH_PREVIOUS, NULL) == FSE_OK) {
         FURI_LOG_D(LOGGING_TAG, "Old config file %s found", CONFIG_FILE_PATH_PREVIOUS);
@@ -63,15 +88,17 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
                 CONFIG_FILE_DIRECTORY_PATH);
             if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
                 FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
-                return NULL;
+                totp_close_config_file(fff_data_file);
+                return TotpConfigFileOpenError;
             }
         }
         if(storage_common_rename(storage, CONFIG_FILE_PATH_PREVIOUS, CONFIG_FILE_PATH) != FSE_OK) {
             FURI_LOG_E(LOGGING_TAG, "Error moving config to %s", CONFIG_FILE_PATH);
-            return NULL;
+            totp_close_config_file(fff_data_file);
+            return TotpConfigFileOpenError;
         }
         FURI_LOG_I(LOGGING_TAG, "Applied config file path migration");
-        return totp_open_config_file(storage);
+        return totp_open_config_file(storage, file);
     } else {
         FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH);
         if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
@@ -81,14 +108,14 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
                 CONFIG_FILE_DIRECTORY_PATH);
             if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
                 FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
-                return NULL;
+                return TotpConfigFileOpenError;
             }
         }
 
         if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) {
             totp_close_config_file(fff_data_file);
             FURI_LOG_E(LOGGING_TAG, "Error creating new file %s", CONFIG_FILE_PATH);
-            return NULL;
+            return TotpConfigFileOpenError;
         }
 
         flipper_format_write_header_cstr(
@@ -153,228 +180,415 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
         if(!flipper_format_rewind(fff_data_file)) {
             totp_close_config_file(fff_data_file);
             FURI_LOG_E(LOGGING_TAG, "Rewind error");
-            return NULL;
+            return TotpConfigFileOpenError;
         }
     }
 
-    return fff_data_file;
+    *file = fff_data_file;
+    return TotpConfigFileOpenSuccess;
 }
 
-void totp_config_file_save_new_token_i(FlipperFormat* file, const TokenInfo* token_info) {
-    flipper_format_seek_to_end(file);
-    flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name);
-    bool token_is_valid = token_info->token != NULL && token_info->token_length > 0;
-    if(!token_is_valid) {
-        flipper_format_write_comment_cstr(file, "!!! WARNING BEGIN: INVALID TOKEN !!!");
-    }
-    flipper_format_write_hex(
-        file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length);
-    if(!token_is_valid) {
-        flipper_format_write_comment_cstr(file, "!!! WARNING END !!!");
-    }
-    flipper_format_write_string_cstr(
-        file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info));
-    uint32_t tmp_uint32 = token_info->digits;
-    flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &tmp_uint32, 1);
+TotpConfigFileUpdateResult
+    totp_config_file_save_new_token_i(FlipperFormat* file, const TokenInfo* token_info) {
+    TotpConfigFileUpdateResult update_result;
+    do {
+        if(!flipper_format_seek_to_end(file)) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name)) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        bool token_is_valid = token_info->token != NULL && token_info->token_length > 0;
+        if(!token_is_valid &&
+           !flipper_format_write_comment_cstr(file, "!!! WARNING BEGIN: INVALID TOKEN !!!")) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_hex(
+               file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length)) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!token_is_valid && !flipper_format_write_comment_cstr(file, "!!! WARNING END !!!")) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_string_cstr(
+               file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info))) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        uint32_t tmp_uint32 = token_info->digits;
+        if(!flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &tmp_uint32, 1)) {
+            update_result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        update_result = TotpConfigFileUpdateSuccess;
+    } while(false);
+
+    return update_result;
 }
 
-void totp_config_file_save_new_token(const TokenInfo* token_info) {
+TotpConfigFileUpdateResult totp_config_file_save_new_token(const TokenInfo* token_info) {
     Storage* cfg_storage = totp_open_storage();
-    FlipperFormat* file = totp_open_config_file(cfg_storage);
+    FlipperFormat* file;
+    TotpConfigFileUpdateResult update_result;
+
+    if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) {
+        do {
+            if(totp_config_file_save_new_token_i(file, token_info) !=
+               TotpConfigFileUpdateSuccess) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
 
-    totp_config_file_save_new_token_i(file, token_info);
+            update_result = TotpConfigFileUpdateSuccess;
+        } while(false);
+
+        totp_close_config_file(file);
+    } else {
+        update_result = TotpConfigFileUpdateError;
+    }
 
-    totp_close_config_file(file);
     totp_close_storage();
+    return update_result;
 }
 
-void totp_config_file_update_timezone_offset(float new_timezone_offset) {
+TotpConfigFileUpdateResult totp_config_file_update_timezone_offset(float new_timezone_offset) {
     Storage* cfg_storage = totp_open_storage();
-    FlipperFormat* file = totp_open_config_file(cfg_storage);
+    FlipperFormat* file;
+    TotpConfigFileUpdateResult update_result;
+
+    if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) {
+        do {
+            if(!flipper_format_insert_or_update_float(
+                   file, TOTP_CONFIG_KEY_TIMEZONE, &new_timezone_offset, 1)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
 
-    flipper_format_insert_or_update_float(file, TOTP_CONFIG_KEY_TIMEZONE, &new_timezone_offset, 1);
+            update_result = TotpConfigFileUpdateSuccess;
+        } while(false);
+
+        totp_close_config_file(file);
+    } else {
+        update_result = TotpConfigFileUpdateError;
+    }
 
-    totp_close_config_file(file);
     totp_close_storage();
+    return update_result;
 }
 
-void totp_config_file_update_notification_method(NotificationMethod new_notification_method) {
+TotpConfigFileUpdateResult
+    totp_config_file_update_notification_method(NotificationMethod new_notification_method) {
     Storage* cfg_storage = totp_open_storage();
-    FlipperFormat* file = totp_open_config_file(cfg_storage);
+    FlipperFormat* file;
+    TotpConfigFileUpdateResult update_result;
+
+    if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) {
+        do {
+            uint32_t tmp_uint32 = new_notification_method;
+            if(!flipper_format_insert_or_update_uint32(
+                   file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+
+            update_result = TotpConfigFileUpdateSuccess;
+        } while(false);
 
-    uint32_t tmp_uint32 = new_notification_method;
-    flipper_format_insert_or_update_uint32(
-        file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
+        totp_close_config_file(file);
+    } else {
+        update_result = TotpConfigFileUpdateError;
+    }
 
-    totp_close_config_file(file);
     totp_close_storage();
+    return update_result;
 }
 
-void totp_config_file_update_user_settings(const PluginState* plugin_state) {
+TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginState* plugin_state) {
     Storage* cfg_storage = totp_open_storage();
-    FlipperFormat* file = totp_open_config_file(cfg_storage);
+    FlipperFormat* file;
+    TotpConfigFileUpdateResult update_result;
+    if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) {
+        do {
+            if(!flipper_format_insert_or_update_float(
+                   file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+            uint32_t tmp_uint32 = plugin_state->notification_method;
+            if(!flipper_format_insert_or_update_uint32(
+                   file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+
+            update_result = TotpConfigFileUpdateSuccess;
+        } while(false);
 
-    flipper_format_insert_or_update_float(
-        file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
-    uint32_t tmp_uint32 = plugin_state->notification_method;
-    flipper_format_insert_or_update_uint32(
-        file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
+        totp_close_config_file(file);
+    } else {
+        update_result = TotpConfigFileUpdateError;
+    }
 
-    totp_close_config_file(file);
     totp_close_storage();
+    return update_result;
 }
 
-void totp_full_save_config_file(const PluginState* const plugin_state) {
+TotpConfigFileUpdateResult totp_full_save_config_file(const PluginState* const plugin_state) {
     Storage* storage = totp_open_storage();
     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
+    TotpConfigFileUpdateResult result = TotpConfigFileUpdateSuccess;
 
-    flipper_format_file_open_always(fff_data_file, CONFIG_FILE_PATH);
-    flipper_format_write_header_cstr(
-        fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
-    flipper_format_write_hex(
-        fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE);
-    flipper_format_write_hex(
-        fff_data_file,
-        TOTP_CONFIG_KEY_CRYPTO_VERIFY,
-        plugin_state->crypto_verify_data,
-        plugin_state->crypto_verify_data_length);
-    flipper_format_write_float(
-        fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
-    flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
-    uint32_t tmp_uint32 = plugin_state->notification_method;
-    flipper_format_write_uint32(
-        fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
-
-    TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
-        const TokenInfo* token_info = node->data;
-        totp_config_file_save_new_token_i(fff_data_file, token_info);
-    });
+    do {
+        if(!flipper_format_file_open_always(fff_data_file, CONFIG_FILE_TEMP_PATH)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_header_cstr(
+               fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_hex(
+               fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_hex(
+               fff_data_file,
+               TOTP_CONFIG_KEY_CRYPTO_VERIFY,
+               plugin_state->crypto_verify_data,
+               plugin_state->crypto_verify_data_length)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_float(
+               fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        if(!flipper_format_write_bool(
+               fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+        uint32_t tmp_uint32 = plugin_state->notification_method;
+        if(!flipper_format_write_uint32(
+               fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+
+        bool tokens_written = true;
+        TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
+            const TokenInfo* token_info = node->data;
+            tokens_written = tokens_written &&
+                             totp_config_file_save_new_token_i(fff_data_file, token_info) ==
+                                 TotpConfigFileUpdateSuccess;
+        });
+
+        if(!tokens_written) {
+            result = TotpConfigFileUpdateError;
+            break;
+        }
+    } while(false);
 
     totp_close_config_file(fff_data_file);
+
+    if(result == TotpConfigFileUpdateSuccess) {
+        if(storage_file_exists(storage, CONFIG_FILE_ORIG_PATH)) {
+            storage_simply_remove(storage, CONFIG_FILE_ORIG_PATH);
+        }
+
+        if(storage_common_rename(storage, CONFIG_FILE_PATH, CONFIG_FILE_ORIG_PATH) != FSE_OK) {
+            result = TotpConfigFileUpdateError;
+        } else if(storage_common_rename(storage, CONFIG_FILE_TEMP_PATH, CONFIG_FILE_PATH) != FSE_OK) {
+            result = TotpConfigFileUpdateError;
+        } else if(!storage_simply_remove(storage, CONFIG_FILE_ORIG_PATH)) {
+            result = TotpConfigFileUpdateError;
+        }
+    }
+
     totp_close_storage();
+    return result;
 }
 
-void totp_config_file_load_base(PluginState* const plugin_state) {
+TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_state) {
     Storage* storage = totp_open_storage();
-    FlipperFormat* fff_data_file = totp_open_config_file(storage);
+    FlipperFormat* fff_data_file;
+
+    TotpConfigFileOpenResult result;
+    if((result = totp_open_config_file(storage, &fff_data_file)) != TotpConfigFileOpenSuccess) {
+        totp_close_storage();
+        return result;
+    }
 
     plugin_state->timezone_offset = 0;
 
     FuriString* temp_str = furi_string_alloc();
 
-    uint32_t file_version;
-    if(!flipper_format_read_header(fff_data_file, temp_str, &file_version)) {
-        FURI_LOG_E(LOGGING_TAG, "Missing or incorrect header");
-        furi_string_free(temp_str);
-        return;
-    }
+    do {
+        uint32_t file_version;
+        if(!flipper_format_read_header(fff_data_file, temp_str, &file_version)) {
+            FURI_LOG_E(LOGGING_TAG, "Missing or incorrect header");
+            result = TotpConfigFileOpenError;
+            break;
+        }
 
-    if(file_version < CONFIG_FILE_ACTUAL_VERSION) {
-        FURI_LOG_I(
-            LOGGING_TAG,
-            "Obsolete config file version detected. Current version: %" PRIu32
-            "; Actual version: %" PRId16,
-            file_version,
-            CONFIG_FILE_ACTUAL_VERSION);
-        totp_close_config_file(fff_data_file);
+        if(file_version < CONFIG_FILE_ACTUAL_VERSION) {
+            FURI_LOG_I(
+                LOGGING_TAG,
+                "Obsolete config file version detected. Current version: %" PRIu32
+                "; Actual version: %" PRId16,
+                file_version,
+                CONFIG_FILE_ACTUAL_VERSION);
+            totp_close_config_file(fff_data_file);
 
-        if(storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) {
-            storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH);
-        }
+            if(storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) {
+                storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH);
+            }
 
-        if(storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) {
-            FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH);
-            fff_data_file = totp_open_config_file(storage);
-            FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage);
-            flipper_format_file_open_existing(fff_backup_data_file, CONFIG_FILE_BACKUP_PATH);
+            if(storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) {
+                FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH);
+                if(totp_open_config_file(storage, &fff_data_file) != TotpConfigFileOpenSuccess) {
+                    result = TotpConfigFileOpenError;
+                    break;
+                }
 
-            if(file_version == 1) {
-                if(totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
-                    FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
-                } else {
-                    FURI_LOG_W(LOGGING_TAG, "An error occurred during migration from v1 to v2");
+                FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage);
+                if(!flipper_format_file_open_existing(
+                       fff_backup_data_file, CONFIG_FILE_BACKUP_PATH)) {
+                    flipper_format_file_close(fff_backup_data_file);
+                    flipper_format_free(fff_backup_data_file);
+                    result = TotpConfigFileOpenError;
+                    break;
                 }
-            }
 
-            flipper_format_file_close(fff_backup_data_file);
-            flipper_format_free(fff_backup_data_file);
-            flipper_format_rewind(fff_data_file);
-        } else {
-            FURI_LOG_E(
-                LOGGING_TAG,
-                "An error occurred during taking backup of %s into %s before migration",
-                CONFIG_FILE_PATH,
-                CONFIG_FILE_BACKUP_PATH);
+                if(file_version == 1) {
+                    if(totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
+                        FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
+                    } else {
+                        FURI_LOG_W(
+                            LOGGING_TAG, "An error occurred during migration from v1 to v2");
+                        result = TotpConfigFileOpenError;
+                        break;
+                    }
+                }
+
+                flipper_format_file_close(fff_backup_data_file);
+                flipper_format_free(fff_backup_data_file);
+                flipper_format_rewind(fff_data_file);
+            } else {
+                FURI_LOG_E(
+                    LOGGING_TAG,
+                    "An error occurred during taking backup of %s into %s before migration",
+                    CONFIG_FILE_PATH,
+                    CONFIG_FILE_BACKUP_PATH);
+                result = TotpConfigFileOpenError;
+                break;
+            }
         }
-    }
 
-    if(!flipper_format_read_hex(
-           fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
-        FURI_LOG_D(LOGGING_TAG, "Missing base IV");
-    }
+        if(!flipper_format_read_hex(
+               fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
+            FURI_LOG_D(LOGGING_TAG, "Missing base IV");
+        }
 
-    flipper_format_rewind(fff_data_file);
+        if(!flipper_format_rewind(fff_data_file)) {
+            result = TotpConfigFileOpenError;
+            break;
+        }
 
-    uint32_t crypto_size;
-    if(flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
-       crypto_size > 0) {
-        plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
-        furi_check(plugin_state->crypto_verify_data != NULL);
-        plugin_state->crypto_verify_data_length = crypto_size;
-        if(!flipper_format_read_hex(
-               fff_data_file,
-               TOTP_CONFIG_KEY_CRYPTO_VERIFY,
-               plugin_state->crypto_verify_data,
-               crypto_size)) {
-            FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
-            free(plugin_state->crypto_verify_data);
+        uint32_t crypto_size;
+        if(flipper_format_get_value_count(
+               fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
+           crypto_size > 0) {
+            plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
+            furi_check(plugin_state->crypto_verify_data != NULL);
+            plugin_state->crypto_verify_data_length = crypto_size;
+            if(!flipper_format_read_hex(
+                   fff_data_file,
+                   TOTP_CONFIG_KEY_CRYPTO_VERIFY,
+                   plugin_state->crypto_verify_data,
+                   crypto_size)) {
+                FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
+                free(plugin_state->crypto_verify_data);
+                plugin_state->crypto_verify_data = NULL;
+                plugin_state->crypto_verify_data_length = 0;
+            }
+        } else {
             plugin_state->crypto_verify_data = NULL;
             plugin_state->crypto_verify_data_length = 0;
         }
-    } else {
-        plugin_state->crypto_verify_data = NULL;
-        plugin_state->crypto_verify_data_length = 0;
-    }
 
-    flipper_format_rewind(fff_data_file);
+        if(!flipper_format_rewind(fff_data_file)) {
+            result = TotpConfigFileOpenError;
+            break;
+        }
 
-    if(!flipper_format_read_float(
-           fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) {
-        plugin_state->timezone_offset = 0;
-        FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0");
-    }
+        if(!flipper_format_read_float(
+               fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) {
+            plugin_state->timezone_offset = 0;
+            FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0");
+        }
 
-    flipper_format_rewind(fff_data_file);
+        if(!flipper_format_rewind(fff_data_file)) {
+            result = TotpConfigFileOpenError;
+            break;
+        }
 
-    if(!flipper_format_read_bool(
-           fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
-        plugin_state->pin_set = true;
-    }
+        if(!flipper_format_read_bool(
+               fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
+            plugin_state->pin_set = true;
+        }
 
-    flipper_format_rewind(fff_data_file);
+        flipper_format_rewind(fff_data_file);
 
-    uint32_t tmp_uint32;
-    if(!flipper_format_read_uint32(
-           fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
-        tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
-    }
+        uint32_t tmp_uint32;
+        if(!flipper_format_read_uint32(
+               fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
+            tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
+        }
 
-    plugin_state->notification_method = tmp_uint32;
+        plugin_state->notification_method = tmp_uint32;
+    } while(false);
 
     furi_string_free(temp_str);
     totp_close_config_file(fff_data_file);
     totp_close_storage();
+    return result;
 }
 
 TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) {
     Storage* storage = totp_open_storage();
-    FlipperFormat* fff_data_file = totp_open_config_file(storage);
+    FlipperFormat* fff_data_file;
+    if(totp_open_config_file(storage, &fff_data_file) != TotpConfigFileOpenSuccess) {
+        totp_close_storage();
+        return TokenLoadingResultError;
+    }
 
     FuriString* temp_str = furi_string_alloc();
     uint32_t temp_data32;
 
     if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
         FURI_LOG_E(LOGGING_TAG, "Missing or incorrect header");
+        totp_close_storage();
         furi_string_free(temp_str);
         return TokenLoadingResultError;
     }
@@ -478,8 +692,42 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
     return result;
 }
 
-void totp_close_config_file(FlipperFormat* file) {
-    if(file == NULL) return;
-    flipper_format_file_close(file);
-    flipper_format_free(file);
-}
+TotpConfigFileUpdateResult
+    totp_config_file_update_crypto_signatures(const PluginState* plugin_state) {
+    Storage* storage = totp_open_storage();
+    FlipperFormat* config_file;
+    TotpConfigFileUpdateResult update_result;
+    if(totp_open_config_file(storage, &config_file) == TotpConfigFileOpenSuccess) {
+        do {
+            if(!flipper_format_insert_or_update_hex(
+                   config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+
+            if(!flipper_format_insert_or_update_hex(
+                   config_file,
+                   TOTP_CONFIG_KEY_CRYPTO_VERIFY,
+                   plugin_state->crypto_verify_data,
+                   plugin_state->crypto_verify_data_length)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+
+            if(!flipper_format_insert_or_update_bool(
+                   config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
+                update_result = TotpConfigFileUpdateError;
+                break;
+            }
+
+            update_result = TotpConfigFileUpdateSuccess;
+        } while(false);
+
+        totp_close_config_file(config_file);
+    } else {
+        update_result = TotpConfigFileUpdateError;
+    }
+
+    totp_close_storage();
+    return update_result;
+}

+ 45 - 22
services/config/config.h

@@ -7,6 +7,8 @@
 #include "constants.h"
 
 typedef uint8_t TokenLoadingResult;
+typedef uint8_t TotpConfigFileOpenResult;
+typedef uint8_t TotpConfigFileUpdateResult;
 
 /**
  * @brief Token loading results
@@ -29,40 +31,48 @@ enum TokenLoadingResults {
 };
 
 /**
- * @brief Opens storage record
- * @return Storage record
+ * @brief Config file opening result
  */
-Storage* totp_open_storage();
+enum TotpConfigFileOpenResults {
+    /**
+     * @brief Config file opened successfully
+     */
+    TotpConfigFileOpenSuccess = 0,
 
-/**
- * @brief Closes storage record
- */
-void totp_close_storage();
+    /**
+     * @brief An error has occurred during opening config file
+     */
+    TotpConfigFileOpenError = 1
+};
 
 /**
- * @brief Opens or creates TOTP application standard config file
- * @param storage storage record to use
- * @return Config file reference
+ * @brief Config file updating result
  */
-FlipperFormat* totp_open_config_file(Storage* storage);
+enum TotpConfigFileUpdateResults {
+    /**
+     * @brief Config file updated successfully
+     */
+    TotpConfigFileUpdateSuccess,
 
-/**
- * @brief Closes config file
- * @param file config file reference
- */
-void totp_close_config_file(FlipperFormat* file);
+    /**
+     * @brief An error has occurred during updating config file
+     */
+    TotpConfigFileUpdateError
+};
 
 /**
  * @brief Saves all the settings and tokens to an application config file
  * @param plugin_state application state
+ * @return Config file update result
  */
-void totp_full_save_config_file(const PluginState* const plugin_state);
+TotpConfigFileUpdateResult totp_full_save_config_file(const PluginState* const plugin_state);
 
 /**
  * @brief Loads basic information from an application config file into application state without loading all the tokens
  * @param plugin_state application state
+ * @return Config file open result
  */
-void totp_config_file_load_base(PluginState* const plugin_state);
+TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_state);
 
 /**
  * @brief Loads tokens from an application config file into application state
@@ -74,23 +84,36 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
 /**
  * @brief Add new token to the end of the application config file
  * @param token_info token information to be saved
+ * @return Config file update result
  */
-void totp_config_file_save_new_token(const TokenInfo* token_info);
+TotpConfigFileUpdateResult totp_config_file_save_new_token(const TokenInfo* token_info);
 
 /**
  * @brief Updates timezone offset in an application config file
  * @param new_timezone_offset new timezone offset to be set
+ * @return Config file update result
  */
-void totp_config_file_update_timezone_offset(float new_timezone_offset);
+TotpConfigFileUpdateResult totp_config_file_update_timezone_offset(float new_timezone_offset);
 
 /**
  * @brief Updates notification method in an application config file
  * @param new_notification_method new notification method to be set
+ * @return Config file update result
  */
-void totp_config_file_update_notification_method(NotificationMethod new_notification_method);
+TotpConfigFileUpdateResult
+    totp_config_file_update_notification_method(NotificationMethod new_notification_method);
 
 /**
  * @brief Updates application user settings
  * @param plugin_state application state
+ * @return Config file update result
+ */
+TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginState* plugin_state);
+
+/**
+ * @brief Updates crypto signatures information
+ * @param plugin_state application state
+ * @return Config file update result
  */
-void totp_config_file_update_user_settings(const PluginState* plugin_state);
+TotpConfigFileUpdateResult
+    totp_config_file_update_crypto_signatures(const PluginState* plugin_state);

+ 7 - 14
services/crypto/crypto.c

@@ -61,7 +61,7 @@ uint8_t* totp_crypto_decrypt(
     return decrypted_data;
 }
 
-void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
+bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
     if(plugin_state->crypto_verify_data == NULL) {
         FURI_LOG_D(LOGGING_TAG, "Generating new IV");
         furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
@@ -94,13 +94,12 @@ void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t
         }
     }
 
+    bool result = true;
     if(plugin_state->crypto_verify_data == NULL) {
         FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data");
         plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
         furi_check(plugin_state->crypto_verify_data != NULL);
         plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
-        Storage* storage = totp_open_storage();
-        FlipperFormat* config_file = totp_open_config_file(storage);
 
         plugin_state->crypto_verify_data = totp_crypto_encrypt(
             (uint8_t*)CRYPTO_VERIFY_KEY,
@@ -108,19 +107,13 @@ void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t
             &plugin_state->iv[0],
             &plugin_state->crypto_verify_data_length);
 
-        flipper_format_insert_or_update_hex(
-            config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE);
-        flipper_format_insert_or_update_hex(
-            config_file,
-            TOTP_CONFIG_KEY_CRYPTO_VERIFY,
-            plugin_state->crypto_verify_data,
-            CRYPTO_VERIFY_KEY_LENGTH);
         plugin_state->pin_set = pin != NULL && pin_length > 0;
-        flipper_format_insert_or_update_bool(
-            config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
-        totp_close_config_file(config_file);
-        totp_close_storage();
+
+        result = totp_config_file_update_crypto_signatures(plugin_state) ==
+                 TotpConfigFileUpdateSuccess;
     }
+
+    return result;
 }
 
 bool totp_crypto_verify_key(const PluginState* plugin_state) {

+ 2 - 1
services/crypto/crypto.h

@@ -35,8 +35,9 @@ uint8_t* totp_crypto_decrypt(
  * @param plugin_state application state
  * @param pin user's PIN
  * @param pin_length user's PIN length
+ * @return \c true on success; \c false otherwise
  */
-void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length);
+bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length);
 
 /**
  * @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption

+ 0 - 2
services/hmac/memxor.c

@@ -18,8 +18,6 @@
 /* Written by Simon Josefsson.  The interface was inspired by memxor
    in Niels Möller's Nettle. */
 
-/* #include <config.h> */
-
 #include "memxor.h"
 
 void* memxor(void* /*restrict*/ dest, const void* /*restrict*/ src, size_t n) {

+ 33 - 17
totp_app.c

@@ -15,6 +15,7 @@
 #include "types/common.h"
 #include "ui/scene_director.h"
 #include "ui/constants.h"
+#include "ui/common_dialogs.h"
 #include "services/crypto/crypto.h"
 #include "cli/cli.h"
 
@@ -36,17 +37,7 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
 }
 
-static bool totp_plugin_state_init(PluginState* const plugin_state) {
-    plugin_state->gui = furi_record_open(RECORD_GUI);
-    plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
-    plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
-
-    totp_config_file_load_base(plugin_state);
-
-    totp_cli_register_command_handler(plugin_state);
-
-    totp_scene_director_init_scenes(plugin_state);
-
+static bool totp_activate_initial_scene(PluginState* const plugin_state) {
     if(plugin_state->crypto_verify_data == NULL) {
         DialogMessage* message = dialog_message_alloc();
         dialog_message_set_buttons(message, "No", NULL, "Yes");
@@ -63,13 +54,19 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
         if(dialog_result == DialogMessageButtonRight) {
             totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
         } else {
-            totp_crypto_seed_iv(plugin_state, NULL, 0);
+            if(!totp_crypto_seed_iv(plugin_state, NULL, 0)) {
+                totp_dialogs_config_loading_error(plugin_state);
+                return false;
+            }
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
         }
     } else if(plugin_state->pin_set) {
         totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
     } else {
-        totp_crypto_seed_iv(plugin_state, NULL, 0);
+        if(!totp_crypto_seed_iv(plugin_state, NULL, 0)) {
+            totp_dialogs_config_loading_error(plugin_state);
+            return false;
+        }
         if(totp_crypto_verify_key(plugin_state)) {
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
         } else {
@@ -94,13 +91,20 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
     return true;
 }
 
-static void totp_plugin_state_free(PluginState* plugin_state) {
-    totp_cli_unregister_command_handler();
+static bool totp_plugin_state_init(PluginState* const plugin_state) {
+    plugin_state->gui = furi_record_open(RECORD_GUI);
+    plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
+    plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
 
-    totp_scene_director_deactivate_active_scene(plugin_state);
+    if(totp_config_file_load_base(plugin_state) != TotpConfigFileOpenSuccess) {
+        totp_dialogs_config_loading_error(plugin_state);
+        return false;
+    }
 
-    totp_scene_director_dispose(plugin_state);
+    return true;
+}
 
+static void totp_plugin_state_free(PluginState* plugin_state) {
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_NOTIFICATION);
     furi_record_close(RECORD_DIALOGS);
@@ -139,6 +143,14 @@ int32_t totp_app() {
         return 255;
     }
 
+    totp_cli_register_command_handler(plugin_state);
+    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");
+        totp_plugin_state_free(plugin_state);
+        return 253;
+    }
+
     // Set system callbacks
     ViewPort* view_port = view_port_alloc();
     view_port_draw_callback_set(view_port, render_callback, &state_mutex);
@@ -171,6 +183,10 @@ int32_t totp_app() {
         release_mutex(&state_mutex, plugin_state_m);
     }
 
+    totp_cli_unregister_command_handler();
+    totp_scene_director_deactivate_active_scene(plugin_state);
+    totp_scene_director_dispose(plugin_state);
+
     view_port_enabled_set(view_port, false);
     gui_remove_view_port(plugin_state->gui, view_port);
     view_port_free(view_port);

+ 20 - 0
ui/common_dialogs.c

@@ -0,0 +1,20 @@
+#include "common_dialogs.h"
+#include "constants.h"
+
+static DialogMessageButton totp_dialogs_common(PluginState* plugin_state, const char* text) {
+    DialogMessage* message = dialog_message_alloc();
+    dialog_message_set_buttons(message, "Exit", NULL, NULL);
+    dialog_message_set_text(
+        message, text, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter);
+    DialogMessageButton result = dialog_message_show(plugin_state->dialogs_app, message);
+    dialog_message_free(message);
+    return result;
+}
+
+DialogMessageButton totp_dialogs_config_loading_error(PluginState* plugin_state) {
+    return totp_dialogs_common(plugin_state, "An error has occurred\nduring loading config file");
+}
+
+DialogMessageButton totp_dialogs_config_updating_error(PluginState* plugin_state) {
+    return totp_dialogs_common(plugin_state, "An error has occurred\nduring updating config file");
+}

+ 7 - 0
ui/common_dialogs.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include <dialogs/dialogs.h>
+#include "../types/plugin_state.h"
+
+DialogMessageButton totp_dialogs_config_loading_error(PluginState* plugin_state);
+DialogMessageButton totp_dialogs_config_updating_error(PluginState* plugin_state);

+ 6 - 1
ui/scenes/add_new_token/totp_scene_add_new_token.c

@@ -7,6 +7,7 @@
 #include "../../../lib/list/list.h"
 #include "../../../services/config/config.h"
 #include "../../ui_controls.h"
+#include "../../common_dialogs.h"
 #include "../../../lib/roll_value/roll_value.h"
 #include "../../../types/nullable.h"
 #include "../generate_token/totp_scene_generate_token.h"
@@ -248,7 +249,11 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
                 TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);
                 plugin_state->tokens_count++;
 
-                totp_config_file_save_new_token(tokenInfo);
+                if(totp_config_file_save_new_token(tokenInfo) != TotpConfigFileUpdateSuccess) {
+                    token_info_free(tokenInfo);
+                    totp_dialogs_config_updating_error(plugin_state);
+                    return false;
+                }
 
                 GenerateTokenSceneContext generate_scene_context = {
                     .current_token_index = plugin_state->tokens_count - 1};

+ 7 - 1
ui/scenes/app_settings/totp_app_settings.c

@@ -2,6 +2,7 @@
 #include <math.h>
 #include <totp_icons.h>
 #include "../../ui_controls.h"
+#include "../../common_dialogs.h"
 #include "../../scene_director.h"
 #include "../token_menu/totp_scene_token_menu.h"
 #include "../../constants.h"
@@ -202,7 +203,12 @@ bool totp_scene_app_settings_handle_event(
                                                    NotificationMethodNone) |
                 (scene_state->notification_vibro ? NotificationMethodVibro :
                                                    NotificationMethodNone);
-            totp_config_file_update_user_settings(plugin_state);
+
+            if(totp_config_file_update_user_settings(plugin_state) !=
+               TotpConfigFileUpdateSuccess) {
+                totp_dialogs_config_updating_error(plugin_state);
+                return false;
+            }
 
             if(!scene_state->current_token_index.is_null) {
                 TokenMenuSceneContext generate_scene_context = {

+ 2 - 2
ui/scenes/generate_token/totp_scene_generate_token.c

@@ -128,7 +128,7 @@ static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount
     str[len] = '\0';
 }
 
-TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
+static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
     switch(algo) {
     case SHA1:
         return TOTP_ALGO_SHA1;
@@ -143,7 +143,7 @@ TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
     return NULL;
 }
 
-void update_totp_params(PluginState* const plugin_state) {
+static void update_totp_params(PluginState* const plugin_state) {
     SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
 
     if(scene_state->current_token_index < plugin_state->tokens_count) {

+ 5 - 1
ui/scenes/token_menu/totp_scene_token_menu.c

@@ -2,6 +2,7 @@
 #include <gui/gui.h>
 #include <dialogs/dialogs.h>
 #include "../../ui_controls.h"
+#include "../../common_dialogs.h"
 #include "../../constants.h"
 #include "../../scene_director.h"
 #include "../../../services/config/config.h"
@@ -156,7 +157,10 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
                 furi_check(tokenInfo != NULL);
                 token_info_free(tokenInfo);
 
-                totp_full_save_config_file(plugin_state);
+                if(totp_full_save_config_file(plugin_state) != TotpConfigFileUpdateSuccess) {
+                    totp_dialogs_config_updating_error(plugin_state);
+                    return false;
+                }
                 totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
             }
             break;