diff --git a/applications/plugins/totp/images/totp_arrow_left_8x9.png b/applications/plugins/totp/images/totp_arrow_left_8x9.png new file mode 100644 index 000000000..3bf9121c0 Binary files /dev/null and b/applications/plugins/totp/images/totp_arrow_left_8x9.png differ diff --git a/applications/plugins/totp/images/totp_arrow_right_8x9.png b/applications/plugins/totp/images/totp_arrow_right_8x9.png new file mode 100644 index 000000000..8c6a8bfeb Binary files /dev/null and b/applications/plugins/totp/images/totp_arrow_right_8x9.png differ diff --git a/applications/plugins/totp/scenes/add_new_token/totp_input_text.c b/applications/plugins/totp/scenes/add_new_token/totp_input_text.c index e3a7f68a6..811cd2976 100644 --- a/applications/plugins/totp/scenes/add_new_token/totp_input_text.c +++ b/applications/plugins/totp/scenes/add_new_token/totp_input_text.c @@ -2,6 +2,16 @@ #include #include "../../types/common.h" +size_t strnlen(const char* s, size_t maxlen) { + size_t len; + + for(len = 0; len < maxlen; len++, s++) { + if(!*s) break; + } + + return len; +} + void view_draw(View* view, Canvas* canvas) { furi_assert(view); if(view->draw_callback) { @@ -32,10 +42,14 @@ static void commit_text_input_callback(void* context) { InputTextSceneState* text_input_state = (InputTextSceneState*)context; if(text_input_state->callback != 0) { InputTextSceneCallbackResult* result = malloc(sizeof(InputTextSceneCallbackResult)); - result->user_input_length = strlen(text_input_state->text_input_buffer); + result->user_input_length = + strnlen(text_input_state->text_input_buffer, INPUT_BUFFER_SIZE); result->user_input = malloc(result->user_input_length + 1); result->callback_data = text_input_state->callback_data; - strcpy(result->user_input, text_input_state->text_input_buffer); + strlcpy( + result->user_input, + text_input_state->text_input_buffer, + result->user_input_length + 1); text_input_state->callback(result); } } diff --git a/applications/plugins/totp/scenes/add_new_token/totp_input_text.h b/applications/plugins/totp/scenes/add_new_token/totp_input_text.h index a73a227b5..dda0dc301 100644 --- a/applications/plugins/totp/scenes/add_new_token/totp_input_text.h +++ b/applications/plugins/totp/scenes/add_new_token/totp_input_text.h @@ -10,7 +10,7 @@ typedef struct { char* user_input; - uint8_t user_input_length; + size_t user_input_length; void* callback_data; } InputTextSceneCallbackResult; diff --git a/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.c b/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.c index fc39b66cd..ff8cc5f38 100644 --- a/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.c +++ b/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.c @@ -8,6 +8,8 @@ #include "../../services/base32/base32.h" #include "../../services/config/config.h" #include "../../services/ui/ui_controls.h" +#include "../../services/roll_value/roll_value.h" +#include "../../services/nullable/nullable.h" #include "../generate_token/totp_scene_generate_token.h" #define TOKEN_ALGO_LIST_LENGTH 3 @@ -25,22 +27,22 @@ typedef enum { typedef struct { char* token_name; - uint8_t token_name_length; + size_t token_name_length; char* token_secret; - uint8_t token_secret_length; + size_t token_secret_length; bool saved; Control selected_control; InputTextSceneContext* token_name_input_context; InputTextSceneContext* token_secret_input_context; InputTextSceneState* input_state; uint32_t input_started_at; - int16_t current_token_index; - int32_t screen_y_offset; + TotpNullable_uint16_t current_token_index; + int16_t screen_y_offset; TokenHashAlgo algo; TokenDigitsCount digits_count; } SceneState; -void totp_scene_add_new_token_init(PluginState* plugin_state) { +void totp_scene_add_new_token_init(const PluginState* plugin_state) { UNUSED(plugin_state); } @@ -87,9 +89,9 @@ void totp_scene_add_new_token_activate( scene_state->input_state = NULL; if(context == NULL) { - scene_state->current_token_index = -1; + TOTP_NULLABLE_NULL(scene_state->current_token_index); } else { - scene_state->current_token_index = context->current_token_index; + TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index); } } @@ -150,141 +152,148 @@ void update_screen_y_offset(SceneState* scene_state) { } bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state) { - if(event->type == EventTypeKey) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(scene_state->input_started_at > 0 && - furi_get_tick() - scene_state->input_started_at > 300) { - return totp_input_text_handle_event(event, scene_state->input_state); - } - - if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { - return false; - } else if(event->input.type == InputTypePress) { - switch(event->input.key) { - case InputKeyUp: - if(scene_state->selected_control > TokenNameTextBox) { - scene_state->selected_control--; - update_screen_y_offset(scene_state); - } - break; - case InputKeyDown: - if(scene_state->selected_control < ConfirmButton) { - scene_state->selected_control++; - update_screen_y_offset(scene_state); - } - break; - case InputKeyRight: - if(scene_state->selected_control == TokenAlgoSelect) { - if(scene_state->algo < SHA512) { - scene_state->algo++; - } else { - scene_state->algo = SHA1; - } - } else if(scene_state->selected_control == TokenLengthSelect) { - if(scene_state->digits_count < TOTP_8_DIGITS) { - scene_state->digits_count++; - } else { - scene_state->digits_count = TOTP_6_DIGITS; - } - } - break; - case InputKeyLeft: - if(scene_state->selected_control == TokenAlgoSelect) { - if(scene_state->algo > SHA1) { - scene_state->algo--; - } else { - scene_state->algo = SHA512; - } - } else if(scene_state->selected_control == TokenLengthSelect) { - if(scene_state->digits_count > TOTP_6_DIGITS) { - scene_state->digits_count--; - } else { - scene_state->digits_count = TOTP_8_DIGITS; - } - } - break; - case InputKeyOk: - switch(scene_state->selected_control) { - case TokenNameTextBox: - if(scene_state->input_state != NULL) { - totp_input_text_free(scene_state->input_state); - } - scene_state->input_state = - totp_input_text_activate(scene_state->token_name_input_context); - scene_state->input_started_at = furi_get_tick(); - break; - case TokenSecretTextBox: - if(scene_state->input_state != NULL) { - totp_input_text_free(scene_state->input_state); - } - scene_state->input_state = - totp_input_text_activate(scene_state->token_secret_input_context); - scene_state->input_started_at = furi_get_tick(); - break; - case TokenAlgoSelect: - break; - case TokenLengthSelect: - break; - case ConfirmButton: { - TokenInfo* tokenInfo = token_info_alloc(); - bool token_secret_set = token_info_set_secret( - tokenInfo, - scene_state->token_secret, - scene_state->token_secret_length, - &plugin_state->iv[0]); - - if(token_secret_set) { - tokenInfo->name = malloc(scene_state->token_name_length + 1); - strcpy(tokenInfo->name, scene_state->token_name); - tokenInfo->algo = scene_state->algo; - tokenInfo->digits = scene_state->digits_count; - - if(plugin_state->tokens_list == NULL) { - plugin_state->tokens_list = list_init_head(tokenInfo); - } else { - list_add(plugin_state->tokens_list, tokenInfo); - } - plugin_state->tokens_count++; - - totp_config_file_save_new_token(tokenInfo); - - GenerateTokenSceneContext generate_scene_context = { - .current_token_index = plugin_state->tokens_count - 1}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneGenerateToken, &generate_scene_context); - } else { - token_info_free(tokenInfo); - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_buttons(message, "Back", NULL, NULL); - dialog_message_set_text( - message, - "Token secret is invalid", - SCREEN_WIDTH_CENTER, - SCREEN_HEIGHT_CENTER, - AlignCenter, - AlignCenter); - dialog_message_show(plugin_state->dialogs, message); - dialog_message_free(message); - scene_state->selected_control = TokenSecretTextBox; - update_screen_y_offset(scene_state); - } - break; - } - } - break; - case InputKeyBack: - if(scene_state->current_token_index >= 0) { - GenerateTokenSceneContext generate_scene_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneGenerateToken, &generate_scene_context); - } else { - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); - } - break; - } - } + if(event->type != EventTypeKey) { + return true; } + + SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + if(scene_state->input_started_at > 0 && + furi_get_tick() - scene_state->input_started_at > 300) { + return totp_input_text_handle_event(event, scene_state->input_state); + } + + if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { + return false; + } + + if(event->input.type != InputTypePress) { + return true; + } + + switch(event->input.key) { + case InputKeyUp: + totp_roll_value_uint8_t( + &scene_state->selected_control, + -1, + TokenNameTextBox, + ConfirmButton, + RollOverflowBehaviorStop); + update_screen_y_offset(scene_state); + break; + case InputKeyDown: + totp_roll_value_uint8_t( + &scene_state->selected_control, + 1, + TokenNameTextBox, + ConfirmButton, + RollOverflowBehaviorStop); + update_screen_y_offset(scene_state); + break; + case InputKeyRight: + if(scene_state->selected_control == TokenAlgoSelect) { + totp_roll_value_uint8_t(&scene_state->algo, 1, SHA1, SHA512, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenLengthSelect) { + totp_roll_value_uint8_t( + &scene_state->digits_count, + 1, + TOTP_6_DIGITS, + TOTP_8_DIGITS, + RollOverflowBehaviorRoll); + } + break; + case InputKeyLeft: + if(scene_state->selected_control == TokenAlgoSelect) { + totp_roll_value_uint8_t( + &scene_state->algo, -1, SHA1, SHA512, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenLengthSelect) { + totp_roll_value_uint8_t( + &scene_state->digits_count, + -1, + TOTP_6_DIGITS, + TOTP_8_DIGITS, + RollOverflowBehaviorRoll); + } + break; + case InputKeyOk: + switch(scene_state->selected_control) { + case TokenNameTextBox: + if(scene_state->input_state != NULL) { + totp_input_text_free(scene_state->input_state); + } + scene_state->input_state = + totp_input_text_activate(scene_state->token_name_input_context); + scene_state->input_started_at = furi_get_tick(); + break; + case TokenSecretTextBox: + if(scene_state->input_state != NULL) { + totp_input_text_free(scene_state->input_state); + } + scene_state->input_state = + totp_input_text_activate(scene_state->token_secret_input_context); + scene_state->input_started_at = furi_get_tick(); + break; + case TokenAlgoSelect: + break; + case TokenLengthSelect: + break; + case ConfirmButton: { + TokenInfo* tokenInfo = token_info_alloc(); + bool token_secret_set = token_info_set_secret( + tokenInfo, + scene_state->token_secret, + scene_state->token_secret_length, + &plugin_state->iv[0]); + + if(token_secret_set) { + tokenInfo->name = malloc(scene_state->token_name_length + 1); + strlcpy( + tokenInfo->name, scene_state->token_name, scene_state->token_name_length + 1); + tokenInfo->algo = scene_state->algo; + tokenInfo->digits = scene_state->digits_count; + + TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo); + plugin_state->tokens_count++; + + totp_config_file_save_new_token(tokenInfo); + + GenerateTokenSceneContext generate_scene_context = { + .current_token_index = plugin_state->tokens_count - 1}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneGenerateToken, &generate_scene_context); + } else { + token_info_free(tokenInfo); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_set_text( + message, + "Token secret is invalid", + SCREEN_WIDTH_CENTER, + SCREEN_HEIGHT_CENTER, + AlignCenter, + AlignCenter); + dialog_message_show(plugin_state->dialogs, message); + dialog_message_free(message); + scene_state->selected_control = TokenSecretTextBox; + update_screen_y_offset(scene_state); + } + break; + } + } + break; + case InputKeyBack: + if(!scene_state->current_token_index.is_null) { + GenerateTokenSceneContext generate_scene_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneGenerateToken, &generate_scene_context); + } else { + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); + } + break; + default: + break; + } + return true; } @@ -308,6 +317,6 @@ void totp_scene_add_new_token_deactivate(PluginState* plugin_state) { plugin_state->current_scene_state = NULL; } -void totp_scene_add_new_token_free(PluginState* plugin_state) { +void totp_scene_add_new_token_free(const PluginState* plugin_state) { UNUSED(plugin_state); } diff --git a/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.h b/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.h index b65c567a2..9f53fe799 100644 --- a/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.h +++ b/applications/plugins/totp/scenes/add_new_token/totp_scene_add_new_token.h @@ -7,14 +7,14 @@ #include "../../types/plugin_event.h" typedef struct { - uint8_t current_token_index; + uint16_t current_token_index; } TokenAddEditSceneContext; -void totp_scene_add_new_token_init(PluginState* plugin_state); +void totp_scene_add_new_token_init(const PluginState* plugin_state); void totp_scene_add_new_token_activate( PluginState* plugin_state, const TokenAddEditSceneContext* context); void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state); bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state); void totp_scene_add_new_token_deactivate(PluginState* plugin_state); -void totp_scene_add_new_token_free(PluginState* plugin_state); +void totp_scene_add_new_token_free(const PluginState* plugin_state); diff --git a/applications/plugins/totp/scenes/app_settings/totp_app_settings.c b/applications/plugins/totp/scenes/app_settings/totp_app_settings.c index cdb775a8d..b5b75db71 100644 --- a/applications/plugins/totp/scenes/app_settings/totp_app_settings.c +++ b/applications/plugins/totp/scenes/app_settings/totp_app_settings.c @@ -4,6 +4,8 @@ #include "../token_menu/totp_scene_token_menu.h" #include "../../services/ui/constants.h" #include "../../services/config/config.h" +#include "../../services/roll_value/roll_value.h" +#include "../../services/nullable/nullable.h" #define DIGIT_TO_CHAR(digit) ((digit) + '0') @@ -12,11 +14,11 @@ typedef enum { HoursInput, MinutesInput, ConfirmButton } Control; typedef struct { int8_t tz_offset_hours; uint8_t tz_offset_minutes; - int16_t current_token_index; + TotpNullable_uint16_t current_token_index; Control selected_control; } SceneState; -void totp_scene_app_settings_init(PluginState* plugin_state) { +void totp_scene_app_settings_init(const PluginState* plugin_state) { UNUSED(plugin_state); } @@ -26,9 +28,9 @@ void totp_scene_app_settings_activate( SceneState* scene_state = malloc(sizeof(SceneState)); plugin_state->current_scene_state = scene_state; if(context != NULL) { - scene_state->current_token_index = context->current_token_index; + TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index); } else { - scene_state->current_token_index = -1; + TOTP_NULLABLE_NULL(scene_state->current_token_index); } float off_int; @@ -53,7 +55,7 @@ static void two_digit_to_str(int8_t num, char* str) { } void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Timezone offset"); @@ -90,77 +92,80 @@ void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_st scene_state->selected_control == ConfirmButton); } -bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state) { - if(event->type == EventTypeKey) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(event->input.type == InputTypePress) { - switch(event->input.key) { - case InputKeyUp: - if(scene_state->selected_control > HoursInput) { - scene_state->selected_control--; - } - break; - case InputKeyDown: - if(scene_state->selected_control < ConfirmButton) { - scene_state->selected_control++; - } - break; - case InputKeyRight: - if(scene_state->selected_control == HoursInput) { - if(scene_state->tz_offset_hours < 12) { - scene_state->tz_offset_hours++; - } - } else if(scene_state->selected_control == MinutesInput) { - if(scene_state->tz_offset_minutes < 45) { - scene_state->tz_offset_minutes += 15; - } else { - scene_state->tz_offset_minutes = 0; - } - } - break; - case InputKeyLeft: - if(scene_state->selected_control == HoursInput) { - if(scene_state->tz_offset_hours > -12) { - scene_state->tz_offset_hours--; - } - } else if(scene_state->selected_control == MinutesInput) { - if(scene_state->tz_offset_minutes >= 15) { - scene_state->tz_offset_minutes -= 15; - } else { - scene_state->tz_offset_minutes = 45; - } - } - break; - case InputKeyOk: - if(scene_state->selected_control == ConfirmButton) { - plugin_state->timezone_offset = (float)scene_state->tz_offset_hours + - (float)scene_state->tz_offset_minutes / 60.0f; - totp_config_file_update_timezone_offset(plugin_state->timezone_offset); +bool totp_scene_app_settings_handle_event( + const PluginEvent* const event, + PluginState* plugin_state) { + if(event->type != EventTypeKey) { + return true; + } - if(scene_state->current_token_index >= 0) { - TokenMenuSceneContext generate_scene_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneTokenMenu, &generate_scene_context); - } else { - totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); - } - } - break; - case InputKeyBack: { - if(scene_state->current_token_index >= 0) { - TokenMenuSceneContext generate_scene_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneTokenMenu, &generate_scene_context); - } else { - totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); - } - break; - } + SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + if(event->input.type != InputTypePress) { + return true; + } + + switch(event->input.key) { + case InputKeyUp: + totp_roll_value_uint8_t( + &scene_state->selected_control, + -1, + HoursInput, + ConfirmButton, + RollOverflowBehaviorStop); + break; + case InputKeyDown: + totp_roll_value_uint8_t( + &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop); + break; + case InputKeyRight: + if(scene_state->selected_control == HoursInput) { + totp_roll_value_int8_t( + &scene_state->tz_offset_hours, 1, -12, 12, RollOverflowBehaviorStop); + } else if(scene_state->selected_control == MinutesInput) { + totp_roll_value_uint8_t( + &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll); + } + break; + case InputKeyLeft: + if(scene_state->selected_control == HoursInput) { + totp_roll_value_int8_t( + &scene_state->tz_offset_hours, -1, -12, 12, RollOverflowBehaviorStop); + } else if(scene_state->selected_control == MinutesInput) { + totp_roll_value_uint8_t( + &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll); + } + break; + case InputKeyOk: + if(scene_state->selected_control == ConfirmButton) { + plugin_state->timezone_offset = (float)scene_state->tz_offset_hours + + (float)scene_state->tz_offset_minutes / 60.0f; + totp_config_file_update_timezone_offset(plugin_state->timezone_offset); + + if(!scene_state->current_token_index.is_null) { + TokenMenuSceneContext generate_scene_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneTokenMenu, &generate_scene_context); + } else { + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); } } + break; + case InputKeyBack: { + if(!scene_state->current_token_index.is_null) { + TokenMenuSceneContext generate_scene_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneTokenMenu, &generate_scene_context); + } else { + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); + } + break; } + default: + break; + } + return true; } @@ -171,6 +176,6 @@ void totp_scene_app_settings_deactivate(PluginState* plugin_state) { plugin_state->current_scene_state = NULL; } -void totp_scene_app_settings_free(PluginState* plugin_state) { +void totp_scene_app_settings_free(const PluginState* plugin_state) { UNUSED(plugin_state); } \ No newline at end of file diff --git a/applications/plugins/totp/scenes/app_settings/totp_app_settings.h b/applications/plugins/totp/scenes/app_settings/totp_app_settings.h index b97de3390..bcf930839 100644 --- a/applications/plugins/totp/scenes/app_settings/totp_app_settings.h +++ b/applications/plugins/totp/scenes/app_settings/totp_app_settings.h @@ -7,14 +7,16 @@ #include "../../types/plugin_event.h" typedef struct { - uint8_t current_token_index; + uint16_t current_token_index; } AppSettingsSceneContext; -void totp_scene_app_settings_init(PluginState* plugin_state); +void totp_scene_app_settings_init(const PluginState* plugin_state); void totp_scene_app_settings_activate( PluginState* plugin_state, const AppSettingsSceneContext* context); void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state); -bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state); +bool totp_scene_app_settings_handle_event( + const PluginEvent* const event, + PluginState* plugin_state); void totp_scene_app_settings_deactivate(PluginState* plugin_state); -void totp_scene_app_settings_free(PluginState* plugin_state); \ No newline at end of file +void totp_scene_app_settings_free(const PluginState* plugin_state); \ No newline at end of file diff --git a/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.c b/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.c index 4ed79accd..8f44653ec 100644 --- a/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.c +++ b/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.c @@ -1,7 +1,7 @@ #include "totp_scene_authenticate.h" #include +#include #include "../../types/common.h" -#include "../../services/ui/icons.h" #include "../../services/ui/constants.h" #include "../../services/config/config.h" #include "../scene_director.h" @@ -9,6 +9,10 @@ #include "../../services/crypto/crypto.h" #define MAX_CODE_LENGTH TOTP_IV_SIZE +#define ARROW_UP_CODE 2 +#define ARROW_RIGHT_CODE 8 +#define ARROW_DOWN_CODE 11 +#define ARROW_LEFT_CODE 5 typedef struct { uint8_t code_input[MAX_CODE_LENGTH]; @@ -28,7 +32,7 @@ void totp_scene_authenticate_activate(PluginState* plugin_state) { } void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; int v_shift = 0; if(scene_state->code_length > 0) { @@ -73,78 +77,82 @@ void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_st } } -bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState* plugin_state) { - if(event->type == EventTypeKey) { - if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { - return false; - } else if(event->input.type == InputTypePress) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; +bool totp_scene_authenticate_handle_event( + const PluginEvent* const event, + PluginState* plugin_state) { + if(event->type != EventTypeKey) { + return true; + } - const uint8_t ARROW_UP_CODE = 2; - const uint8_t ARROW_RIGHT_CODE = 8; - const uint8_t ARROW_DOWN_CODE = 11; - const uint8_t ARROW_LEFT_CODE = 5; + if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { + return false; + } - switch(event->input.key) { - case InputKeyUp: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = ARROW_UP_CODE; - scene_state->code_length++; - } - break; - case InputKeyDown: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = ARROW_DOWN_CODE; - scene_state->code_length++; - } - break; - case InputKeyRight: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = ARROW_RIGHT_CODE; - scene_state->code_length++; - } - break; - case InputKeyLeft: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = ARROW_LEFT_CODE; - scene_state->code_length++; - } - break; - case InputKeyOk: - totp_crypto_seed_iv( - plugin_state, &scene_state->code_input[0], scene_state->code_length); + if(event->input.type != InputTypePress) { + return true; + } - if(totp_crypto_verify_key(plugin_state)) { - FURI_LOG_D(LOGGING_TAG, "PIN is valid"); - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); - } else { - FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid"); - memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); - memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); - scene_state->code_length = 0; + SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_buttons(message, "Try again", NULL, NULL); - dialog_message_set_header( - message, - "You entered\ninvalid PIN", - SCREEN_WIDTH_CENTER - 25, - SCREEN_HEIGHT_CENTER - 5, - AlignCenter, - AlignCenter); - dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); - dialog_message_show(plugin_state->dialogs, message); - dialog_message_free(message); - } - break; - case InputKeyBack: - if(scene_state->code_length > 0) { - scene_state->code_input[scene_state->code_length - 1] = 0; - scene_state->code_length--; - } - break; - } + switch(event->input.key) { + case InputKeyUp: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = ARROW_UP_CODE; + scene_state->code_length++; } + break; + case InputKeyDown: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = ARROW_DOWN_CODE; + scene_state->code_length++; + } + break; + case InputKeyRight: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = ARROW_RIGHT_CODE; + scene_state->code_length++; + } + break; + case InputKeyLeft: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = ARROW_LEFT_CODE; + scene_state->code_length++; + } + break; + case InputKeyOk: + totp_crypto_seed_iv(plugin_state, &scene_state->code_input[0], scene_state->code_length); + + if(totp_crypto_verify_key(plugin_state)) { + FURI_LOG_D(LOGGING_TAG, "PIN is valid"); + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); + } else { + FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid"); + memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); + memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); + scene_state->code_length = 0; + + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_buttons(message, "Try again", NULL, NULL); + dialog_message_set_header( + message, + "You entered\ninvalid PIN", + SCREEN_WIDTH_CENTER - 25, + SCREEN_HEIGHT_CENTER - 5, + AlignCenter, + AlignCenter); + dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); + dialog_message_show(plugin_state->dialogs, message); + dialog_message_free(message); + } + break; + case InputKeyBack: + if(scene_state->code_length > 0) { + scene_state->code_input[scene_state->code_length - 1] = 0; + scene_state->code_length--; + } + break; + default: + break; } return true; @@ -156,6 +164,6 @@ void totp_scene_authenticate_deactivate(PluginState* plugin_state) { plugin_state->current_scene_state = NULL; } -void totp_scene_authenticate_free(PluginState* plugin_state) { +void totp_scene_authenticate_free(const PluginState* plugin_state) { UNUSED(plugin_state); } diff --git a/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.h b/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.h index f1199a425..c54152f62 100644 --- a/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.h +++ b/applications/plugins/totp/scenes/authenticate/totp_scene_authenticate.h @@ -9,6 +9,8 @@ void totp_scene_authenticate_init(PluginState* plugin_state); void totp_scene_authenticate_activate(PluginState* plugin_state); void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state); -bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState* plugin_state); +bool totp_scene_authenticate_handle_event( + const PluginEvent* const event, + PluginState* plugin_state); void totp_scene_authenticate_deactivate(PluginState* plugin_state); -void totp_scene_authenticate_free(PluginState* plugin_state); +void totp_scene_authenticate_free(const PluginState* plugin_state); diff --git a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c index 674bcd41e..c95e2c4e7 100644 --- a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c @@ -1,14 +1,16 @@ #include #include #include +#include #include "totp_scene_generate_token.h" #include "../../types/token_info.h" #include "../../types/common.h" -#include "../../services/ui/icons.h" #include "../../services/ui/constants.h" #include "../../services/totp/totp.h" #include "../../services/config/config.h" #include "../../services/crypto/crypto.h" +#include "../../services/crypto/memset_s.h" +#include "../../services/roll_value/roll_value.h" #include "../scene_director.h" #include "../token_menu/totp_scene_token_menu.h" @@ -16,7 +18,7 @@ #define DIGIT_TO_CHAR(digit) ((digit) + '0') typedef struct { - uint8_t current_token_index; + uint16_t current_token_index; char last_code[9]; char* last_code_name; bool need_token_update; @@ -95,7 +97,7 @@ void update_totp_params(PluginState* const plugin_state) { } } -void totp_scene_generate_token_init(PluginState* plugin_state) { +void totp_scene_generate_token_init(const PluginState* plugin_state) { UNUSED(plugin_state); } @@ -180,7 +182,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ ->data); if(tokenInfo->token != NULL && tokenInfo->token_length > 0) { - uint8_t key_length; + size_t key_length; uint8_t* key = totp_crypto_decrypt( tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); @@ -195,7 +197,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ TOKEN_LIFETIME), scene_state->last_code, tokenInfo->digits); - memset(key, 0, key_length); + memset_s(key, sizeof(key), 0, key_length); free(key); } else { i_token_to_str(0, scene_state->last_code, tokenInfo->digits); @@ -248,63 +250,63 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ canvas_draw_box(canvas, barX, SCREEN_HEIGHT - BAR_MARGIN - BAR_HEIGHT, barWidth, BAR_HEIGHT); if(plugin_state->tokens_count > 1) { - canvas_draw_xbm( - canvas, - 0, - SCREEN_HEIGHT_CENTER - 24, - ICON_ARROW_LEFT_8x9_WIDTH, - ICON_ARROW_LEFT_8x9_HEIGHT, - &ICON_ARROW_LEFT_8x9[0]); - canvas_draw_xbm( - canvas, - SCREEN_WIDTH - 9, - SCREEN_HEIGHT_CENTER - 24, - ICON_ARROW_RIGHT_8x9_WIDTH, - ICON_ARROW_RIGHT_8x9_HEIGHT, - &ICON_ARROW_RIGHT_8x9[0]); + canvas_draw_icon(canvas, 0, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_left_8x9); + canvas_draw_icon( + canvas, SCREEN_WIDTH - 9, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9); } } -bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state) { - if(event->type == EventTypeKey) { - if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { - return false; - } else if(event->input.type == InputTypePress) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - switch(event->input.key) { - case InputKeyUp: - break; - case InputKeyDown: - break; - case InputKeyRight: - if(scene_state->current_token_index < plugin_state->tokens_count - 1) { - scene_state->current_token_index++; - } else { - scene_state->current_token_index = 0; - } - update_totp_params(plugin_state); - break; - case InputKeyLeft: - if(scene_state->current_token_index > 0) { - scene_state->current_token_index--; - } else { - scene_state->current_token_index = plugin_state->tokens_count - 1; - } - update_totp_params(plugin_state); - break; - case InputKeyOk: - if(plugin_state->tokens_count == 0) { - totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); - } else { - TokenMenuSceneContext ctx = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &ctx); - } - break; - case InputKeyBack: - break; - } +bool totp_scene_generate_token_handle_event( + const PluginEvent* const event, + PluginState* plugin_state) { + if(event->type != EventTypeKey) { + return true; + } + + if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { + return false; + } + + if(event->input.type != InputTypePress) { + return true; + } + + SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + switch(event->input.key) { + case InputKeyUp: + break; + case InputKeyDown: + break; + case InputKeyRight: + totp_roll_value_uint16_t( + &scene_state->current_token_index, + 1, + 0, + plugin_state->tokens_count - 1, + RollOverflowBehaviorRoll); + update_totp_params(plugin_state); + break; + case InputKeyLeft: + totp_roll_value_uint16_t( + &scene_state->current_token_index, + -1, + 0, + plugin_state->tokens_count - 1, + RollOverflowBehaviorRoll); + update_totp_params(plugin_state); + break; + case InputKeyOk: + if(plugin_state->tokens_count == 0) { + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); + } else { + TokenMenuSceneContext ctx = {.current_token_index = scene_state->current_token_index}; + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &ctx); } + break; + case InputKeyBack: + break; + default: + break; } return true; @@ -314,11 +316,10 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { if(plugin_state->current_scene_state == NULL) return; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - free(scene_state->last_code); free(scene_state); plugin_state->current_scene_state = NULL; } -void totp_scene_generate_token_free(PluginState* plugin_state) { +void totp_scene_generate_token_free(const PluginState* plugin_state) { UNUSED(plugin_state); } diff --git a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.h b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.h index 1284c7b41..65f9b84e0 100644 --- a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.h +++ b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.h @@ -7,14 +7,16 @@ #include "../../types/plugin_event.h" typedef struct { - uint8_t current_token_index; + uint16_t current_token_index; } GenerateTokenSceneContext; -void totp_scene_generate_token_init(PluginState* plugin_state); +void totp_scene_generate_token_init(const PluginState* plugin_state); void totp_scene_generate_token_activate( PluginState* plugin_state, const GenerateTokenSceneContext* context); void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state); -bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state); +bool totp_scene_generate_token_handle_event( + const PluginEvent* const event, + PluginState* plugin_state); void totp_scene_generate_token_deactivate(PluginState* plugin_state); -void totp_scene_generate_token_free(PluginState* plugin_state); +void totp_scene_generate_token_free(const PluginState* plugin_state); diff --git a/applications/plugins/totp/scenes/scene_director.c b/applications/plugins/totp/scenes/scene_director.c index d4ddd1768..5265123f5 100644 --- a/applications/plugins/totp/scenes/scene_director.c +++ b/applications/plugins/totp/scenes/scene_director.c @@ -88,7 +88,7 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_ } } -void totp_scene_director_dispose(PluginState* const plugin_state) { +void totp_scene_director_dispose(const PluginState* const plugin_state) { totp_scene_generate_token_free(plugin_state); totp_scene_authenticate_free(plugin_state); totp_scene_add_new_token_free(plugin_state); diff --git a/applications/plugins/totp/scenes/scene_director.h b/applications/plugins/totp/scenes/scene_director.h index 3c25afff6..cc06029d3 100644 --- a/applications/plugins/totp/scenes/scene_director.h +++ b/applications/plugins/totp/scenes/scene_director.h @@ -12,5 +12,5 @@ void totp_scene_director_activate_scene( void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state); void totp_scene_director_init_scenes(PluginState* const plugin_state); void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state); -void totp_scene_director_dispose(PluginState* const plugin_state); +void totp_scene_director_dispose(const PluginState* const plugin_state); bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state); diff --git a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c index 22c37dc2c..fecf4f21e 100644 --- a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c +++ b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c @@ -10,6 +10,8 @@ #include "../generate_token/totp_scene_generate_token.h" #include "../add_new_token/totp_scene_add_new_token.h" #include "../app_settings/totp_app_settings.h" +#include "../../services/nullable/nullable.h" +#include "../../services/roll_value/roll_value.h" #define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3) #define SCREEN_HEIGHT_THIRD_CENTER (SCREEN_HEIGHT_THIRD >> 1) @@ -18,10 +20,10 @@ typedef enum { AddNewToken, DeleteToken, AppSettings } Control; typedef struct { Control selected_control; - int16_t current_token_index; + TotpNullable_uint16_t current_token_index; } SceneState; -void totp_scene_token_menu_init(PluginState* plugin_state) { +void totp_scene_token_menu_init(const PluginState* plugin_state) { UNUSED(plugin_state); } @@ -31,15 +33,15 @@ void totp_scene_token_menu_activate( SceneState* scene_state = malloc(sizeof(SceneState)); plugin_state->current_scene_state = scene_state; if(context != NULL) { - scene_state->current_token_index = context->current_token_index; + TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index); } else { - scene_state->current_token_index = -1; + TOTP_NULLABLE_NULL(scene_state->current_token_index); } } void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(scene_state->current_token_index < 0) { + const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + if(scene_state->current_token_index.is_null) { ui_control_button_render( canvas, SCREEN_WIDTH_CENTER - 36, @@ -84,104 +86,107 @@ void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_stat } } -bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state) { - if(event->type == EventTypeKey) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(event->input.type == InputTypePress) { - switch(event->input.key) { - case InputKeyUp: - if(scene_state->selected_control > AddNewToken) { - scene_state->selected_control--; - if(scene_state->selected_control == DeleteToken && - scene_state->current_token_index < 0) { - scene_state->selected_control--; - } - } else { - scene_state->selected_control = AppSettings; - } - break; - case InputKeyDown: - if(scene_state->selected_control < AppSettings) { - scene_state->selected_control++; - if(scene_state->selected_control == DeleteToken && - scene_state->current_token_index < 0) { - scene_state->selected_control++; - } - } else { - scene_state->selected_control = AddNewToken; - } - break; - case InputKeyRight: - break; - case InputKeyLeft: - break; - case InputKeyOk: - switch(scene_state->selected_control) { - case AddNewToken: { - TokenAddEditSceneContext add_new_token_scene_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneAddNewToken, &add_new_token_scene_context); - break; - } - case DeleteToken: { - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_buttons(message, "No", NULL, "Yes"); - dialog_message_set_header(message, "Confirmation", 0, 0, AlignLeft, AlignTop); - dialog_message_set_text( - message, - "Are you sure want to delete?", - SCREEN_WIDTH_CENTER, - SCREEN_HEIGHT_CENTER, - AlignCenter, - AlignCenter); - DialogMessageButton dialog_result = - dialog_message_show(plugin_state->dialogs, message); - dialog_message_free(message); - if(dialog_result == DialogMessageButtonRight) { - ListNode* list_node = list_element_at( - plugin_state->tokens_list, scene_state->current_token_index); - - TokenInfo* tokenInfo = list_node->data; - token_info_free(tokenInfo); - plugin_state->tokens_list = - list_remove(plugin_state->tokens_list, list_node); - plugin_state->tokens_count--; - - totp_full_save_config_file(plugin_state); - totp_scene_director_activate_scene( - plugin_state, TotpSceneGenerateToken, NULL); - } - break; - } - case AppSettings: { - if(scene_state->current_token_index >= 0) { - AppSettingsSceneContext app_settings_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneAppSettings, &app_settings_context); - } else { - totp_scene_director_activate_scene( - plugin_state, TotpSceneAppSettings, NULL); - } - break; - } - } - break; - case InputKeyBack: { - if(scene_state->current_token_index >= 0) { - GenerateTokenSceneContext generate_scene_context = { - .current_token_index = scene_state->current_token_index}; - totp_scene_director_activate_scene( - plugin_state, TotpSceneGenerateToken, &generate_scene_context); - } else { - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); - } - break; - } - } - } +bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginState* plugin_state) { + if(event->type != EventTypeKey) { + return true; } + + SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + if(event->input.type != InputTypePress) { + return true; + } + + switch(event->input.key) { + case InputKeyUp: + totp_roll_value_uint8_t( + &scene_state->selected_control, -1, AddNewToken, AppSettings, RollOverflowBehaviorRoll); + if(scene_state->selected_control == DeleteToken && + scene_state->current_token_index.is_null) { + scene_state->selected_control--; + } + break; + case InputKeyDown: + totp_roll_value_uint8_t( + &scene_state->selected_control, 1, AddNewToken, AppSettings, RollOverflowBehaviorRoll); + if(scene_state->selected_control == DeleteToken && + scene_state->current_token_index.is_null) { + scene_state->selected_control++; + } + break; + case InputKeyRight: + break; + case InputKeyLeft: + break; + case InputKeyOk: + switch(scene_state->selected_control) { + case AddNewToken: { + if(scene_state->current_token_index.is_null) { + totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken, NULL); + } else { + TokenAddEditSceneContext add_new_token_scene_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneAddNewToken, &add_new_token_scene_context); + } + break; + } + case DeleteToken: { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_buttons(message, "No", NULL, "Yes"); + dialog_message_set_header(message, "Confirmation", 0, 0, AlignLeft, AlignTop); + dialog_message_set_text( + message, + "Are you sure want to delete?", + SCREEN_WIDTH_CENTER, + SCREEN_HEIGHT_CENTER, + AlignCenter, + AlignCenter); + DialogMessageButton dialog_result = + dialog_message_show(plugin_state->dialogs, message); + dialog_message_free(message); + if(dialog_result == DialogMessageButtonRight && + !scene_state->current_token_index.is_null) { + ListNode* list_node = list_element_at( + plugin_state->tokens_list, scene_state->current_token_index.value); + + TokenInfo* tokenInfo = list_node->data; + token_info_free(tokenInfo); + plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node); + plugin_state->tokens_count--; + + totp_full_save_config_file(plugin_state); + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); + } + break; + } + case AppSettings: { + if(!scene_state->current_token_index.is_null) { + AppSettingsSceneContext app_settings_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneAppSettings, &app_settings_context); + } else { + totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings, NULL); + } + break; + } + } + break; + case InputKeyBack: { + if(!scene_state->current_token_index.is_null) { + GenerateTokenSceneContext generate_scene_context = { + .current_token_index = scene_state->current_token_index.value}; + totp_scene_director_activate_scene( + plugin_state, TotpSceneGenerateToken, &generate_scene_context); + } else { + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); + } + break; + } + default: + break; + } + return true; } @@ -192,6 +197,6 @@ void totp_scene_token_menu_deactivate(PluginState* plugin_state) { plugin_state->current_scene_state = NULL; } -void totp_scene_token_menu_free(PluginState* plugin_state) { +void totp_scene_token_menu_free(const PluginState* plugin_state) { UNUSED(plugin_state); } diff --git a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.h b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.h index 0b117cb25..acb499be8 100644 --- a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.h +++ b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.h @@ -7,14 +7,14 @@ #include "../../types/plugin_event.h" typedef struct { - uint8_t current_token_index; + uint16_t current_token_index; } TokenMenuSceneContext; -void totp_scene_token_menu_init(PluginState* plugin_state); +void totp_scene_token_menu_init(const PluginState* plugin_state); void totp_scene_token_menu_activate( PluginState* plugin_state, const TokenMenuSceneContext* context); void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state); -bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state); +bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginState* plugin_state); void totp_scene_token_menu_deactivate(PluginState* plugin_state); -void totp_scene_token_menu_free(PluginState* plugin_state); +void totp_scene_token_menu_free(const PluginState* plugin_state); diff --git a/applications/plugins/totp/services/cli/cli.c b/applications/plugins/totp/services/cli/cli.c index 3a7afdd96..76e58a02d 100644 --- a/applications/plugins/totp/services/cli/cli.c +++ b/applications/plugins/totp/services/cli/cli.c @@ -9,7 +9,7 @@ #include "commands/timezone/timezone.h" #include "commands/help/help.h" -static void totp_cli_print_unknown_command(FuriString* unknown_command) { +static void totp_cli_print_unknown_command(const FuriString* unknown_command) { TOTP_CLI_PRINTF( "Command \"%s\" is unknown. Use \"" TOTP_CLI_COMMAND_HELP "\" command to get list of available commands.", diff --git a/applications/plugins/totp/services/cli/cli_helpers.c b/applications/plugins/totp/services/cli/cli_helpers.c index 81a1e4b77..4a0b8b352 100644 --- a/applications/plugins/totp/services/cli/cli_helpers.c +++ b/applications/plugins/totp/services/cli/cli_helpers.c @@ -1,7 +1,7 @@ #include "cli_helpers.h" #include -bool totp_cli_ensure_authenticated(PluginState* plugin_state, Cli* cli) { +bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) { if(plugin_state->current_scene == TotpSceneAuthentication) { TOTP_CLI_PRINTF("Pleases enter PIN on your flipper device\r\n"); @@ -11,7 +11,6 @@ bool totp_cli_ensure_authenticated(PluginState* plugin_state, Cli* cli) { } TOTP_CLI_DELETE_LAST_LINE(); - fflush(stdout); if(plugin_state->current_scene == TotpSceneAuthentication) { return false; diff --git a/applications/plugins/totp/services/cli/cli_helpers.h b/applications/plugins/totp/services/cli/cli_helpers.h index 216925e50..9b19f926b 100644 --- a/applications/plugins/totp/services/cli/cli_helpers.h +++ b/applications/plugins/totp/services/cli/cli_helpers.h @@ -13,16 +13,28 @@ #define DOCOPT_OPTIONS "[options]" #define DOCOPT_DEFAULT(val) "[default: " val "]" -#define TOTP_CLI_PRINTF(format, ...) \ - _Pragma(STRINGIFY(GCC diagnostic push)); \ - _Pragma(STRINGIFY(GCC diagnostic ignored "-Wdouble-promotion")); \ - printf(format, ##__VA_ARGS__); \ - _Pragma(STRINGIFY(GCC diagnostic pop)); +#define TOTP_CLI_PRINTF(format, ...) \ + do { \ + _Pragma(STRINGIFY(GCC diagnostic push)) \ + _Pragma(STRINGIFY(GCC diagnostic ignored "-Wdouble-promotion")) \ + printf(format, ##__VA_ARGS__); \ + _Pragma(STRINGIFY(GCC diagnostic pop)) \ + } while(false) + +#define TOTP_CLI_DELETE_LAST_LINE() \ + TOTP_CLI_PRINTF("\033[A\33[2K\r"); \ + fflush(stdout) + +#define TOTP_CLI_DELETE_CURRENT_LINE() \ + TOTP_CLI_PRINTF("\33[2K\r"); \ + fflush(stdout) + +#define TOTP_CLI_DELETE_LAST_CHAR() \ + TOTP_CLI_PRINTF("\b \b"); \ + fflush(stdout) -#define TOTP_CLI_DELETE_LAST_LINE() TOTP_CLI_PRINTF("\033[A\33[2K\r") -#define TOTP_CLI_DELETE_CURRENT_LINE() TOTP_CLI_PRINTF("\33[2K\r") #define TOTP_CLI_PRINT_INVALID_ARGUMENTS() \ TOTP_CLI_PRINTF( \ "Invalid command arguments. use \"help\" command to get list of available commands") -bool totp_cli_ensure_authenticated(PluginState* plugin_state, Cli* cli); +bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli); diff --git a/applications/plugins/totp/services/cli/commands/add/add.c b/applications/plugins/totp/services/cli/commands/add/add.c index 41ff5b860..31548c59e 100644 --- a/applications/plugins/totp/services/cli/commands/add/add.c +++ b/applications/plugins/totp/services/cli/commands/add/add.c @@ -14,7 +14,7 @@ #define TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX "-d" #define TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX "-u" -static bool token_info_set_digits_from_str(TokenInfo* token_info, FuriString* str) { +static bool token_info_set_digits_from_str(TokenInfo* token_info, const FuriString* str) { switch(furi_string_get_char(str, 0)) { case '6': token_info->digits = TOTP_6_DIGITS; @@ -27,7 +27,7 @@ static bool token_info_set_digits_from_str(TokenInfo* token_info, FuriString* st return false; } -static bool token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) { +static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) { if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) { token_info->algo = SHA1; return true; @@ -79,10 +79,53 @@ void totp_cli_command_add_docopt_options() { TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) " Show console user input as-is without masking\r\n"); } +static void furi_string_secure_free(FuriString* str) { + for(long i = furi_string_size(str) - 1; i >= 0; i--) { + furi_string_set_char(str, i, '\0'); + } + + 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 case 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(); - const char* temp_cstr; - TokenInfo* token_info = token_info_alloc(); // Reading token name @@ -93,9 +136,9 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl return; } - temp_cstr = furi_string_get_cstr(temp_str); - token_info->name = malloc(strlen(temp_cstr) + 1); - strcpy(token_info->name, temp_cstr); + size_t temp_cstr_len = furi_string_size(temp_str); + token_info->name = malloc(temp_cstr_len + 1); + strlcpy(token_info->name, furi_string_get_cstr(temp_str), temp_cstr_len + 1); // Read optional arguments bool mask_user_input = true; @@ -142,59 +185,25 @@ 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"); - - uint8_t c; - while(cli_read(cli, &c, 1) == 1) { - if(c == CliSymbolAsciiEsc) { - 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"); - furi_string_free(temp_str); - token_info_free(token_info); - return; - } 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(temp_str, c); - } else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) { - size_t temp_str_size = furi_string_size(temp_str); - if(temp_str_size > 0) { - TOTP_CLI_PRINTF("\b \b"); - fflush(stdout); - furi_string_left(temp_str, temp_str_size - 1); - } - } else if(c == CliSymbolAsciiCR) { - cli_nl(); - break; - } - } - - temp_cstr = furi_string_get_cstr(temp_str); - - TOTP_CLI_DELETE_LAST_LINE(); - - if(!totp_cli_ensure_authenticated(plugin_state, cli)) { - furi_string_free(temp_str); + if(!totp_cli_read_secret(cli, temp_str, mask_user_input) || + !totp_cli_ensure_authenticated(plugin_state, cli)) { + furi_string_secure_free(temp_str); token_info_free(token_info); return; } - if(!token_info_set_secret(token_info, temp_cstr, strlen(temp_cstr), plugin_state->iv)) { + if(!token_info_set_secret( + token_info, + furi_string_get_cstr(temp_str), + furi_string_size(temp_str), + plugin_state->iv)) { TOTP_CLI_PRINTF("Token secret seems to be invalid and can not be parsed\r\n"); - furi_string_free(temp_str); + furi_string_secure_free(temp_str); token_info_free(token_info); return; } - furi_string_reset(temp_str); - furi_string_free(temp_str); + furi_string_secure_free(temp_str); bool load_generate_token_scene = false; if(plugin_state->current_scene == TotpSceneGenerateToken) { @@ -202,11 +211,7 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl load_generate_token_scene = true; } - if(plugin_state->tokens_list == NULL) { - plugin_state->tokens_list = list_init_head(token_info); - } else { - list_add(plugin_state->tokens_list, token_info); - } + TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, token_info); plugin_state->tokens_count++; totp_config_file_save_new_token(token_info); diff --git a/applications/plugins/totp/services/config/config.c b/applications/plugins/totp/services/config/config.c index 0854d79ad..e751f7990 100644 --- a/applications/plugins/totp/services/config/config.c +++ b/applications/plugins/totp/services/config/config.c @@ -10,7 +10,7 @@ #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf" #define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup" -static uint8_t token_info_get_digits_as_int(TokenInfo* token_info) { +static uint8_t token_info_get_digits_as_int(const TokenInfo* token_info) { switch(token_info->digits) { case TOTP_6_DIGITS: return 6; @@ -32,7 +32,7 @@ static void token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits } } -static char* token_info_get_algo_as_cstr(TokenInfo* token_info) { +static char* token_info_get_algo_as_cstr(const TokenInfo* token_info) { switch(token_info->algo) { case SHA1: return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME; @@ -45,7 +45,7 @@ static char* token_info_get_algo_as_cstr(TokenInfo* token_info) { return NULL; } -static void token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) { +static void token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) { if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) { token_info->algo = SHA1; } else if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME) == 0) { @@ -152,7 +152,7 @@ FlipperFormat* totp_open_config_file(Storage* storage) { return fff_data_file; } -void totp_config_file_save_new_token_i(FlipperFormat* file, TokenInfo* token_info) { +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; @@ -170,7 +170,7 @@ void totp_config_file_save_new_token_i(FlipperFormat* file, TokenInfo* token_inf flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &digits_count_as_uint32, 1); } -void totp_config_file_save_new_token(TokenInfo* token_info) { +void totp_config_file_save_new_token(const TokenInfo* token_info) { Storage* cfg_storage = totp_open_storage(); FlipperFormat* file = totp_open_config_file(cfg_storage); @@ -190,7 +190,7 @@ void totp_config_file_update_timezone_offset(float new_timezone_offset) { totp_close_storage(); } -void totp_full_save_config_file(PluginState* const plugin_state) { +void totp_full_save_config_file(const PluginState* const plugin_state) { Storage* storage = totp_open_storage(); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); @@ -209,7 +209,7 @@ void totp_full_save_config_file(PluginState* const plugin_state) { flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1); ListNode* node = plugin_state->tokens_list; while(node != NULL) { - TokenInfo* token_info = node->data; + const TokenInfo* token_info = node->data; totp_config_file_save_new_token_i(fff_data_file, token_info); node = node->next; } @@ -333,7 +333,7 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) } TokenLoadingResult result = TokenLoadingResultSuccess; - uint8_t index = 0; + uint16_t index = 0; bool has_any_plain_secret = false; while(true) { @@ -343,9 +343,9 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) TokenInfo* tokenInfo = token_info_alloc(); - const char* temp_cstr = furi_string_get_cstr(temp_str); - tokenInfo->name = (char*)malloc(strlen(temp_cstr) + 1); - strcpy(tokenInfo->name, temp_cstr); + size_t temp_cstr_len = furi_string_size(temp_str); + tokenInfo->name = (char*)malloc(temp_cstr_len + 1); + strlcpy(tokenInfo->name, furi_string_get_cstr(temp_str), temp_cstr_len + 1); uint32_t secret_bytes_count; if(!flipper_format_get_value_count( @@ -355,9 +355,11 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) if(secret_bytes_count == 1) { // Plain secret key if(flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str)) { - temp_cstr = furi_string_get_cstr(temp_str); if(token_info_set_secret( - tokenInfo, temp_cstr, strlen(temp_cstr), &plugin_state->iv[0])) { + tokenInfo, + furi_string_get_cstr(temp_str), + furi_string_size(temp_str), + &plugin_state->iv[0])) { FURI_LOG_W(LOGGING_TAG, "Token \"%s\" has plain secret", tokenInfo->name); } else { tokenInfo->token = NULL; @@ -407,11 +409,7 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name); - if(plugin_state->tokens_list == NULL) { - plugin_state->tokens_list = list_init_head(tokenInfo); - } else { - list_add(plugin_state->tokens_list, tokenInfo); - } + TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo); index++; } @@ -419,7 +417,7 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) plugin_state->tokens_count = index; plugin_state->token_list_loaded = true; - FURI_LOG_D(LOGGING_TAG, "Found %" PRIu8 " tokens", index); + FURI_LOG_D(LOGGING_TAG, "Found %" PRIu16 " tokens", index); furi_string_free(temp_str); totp_close_config_file(fff_data_file); diff --git a/applications/plugins/totp/services/config/config.h b/applications/plugins/totp/services/config/config.h index 76cb40b2c..d452ad4b3 100644 --- a/applications/plugins/totp/services/config/config.h +++ b/applications/plugins/totp/services/config/config.h @@ -16,8 +16,8 @@ Storage* totp_open_storage(); void totp_close_storage(); FlipperFormat* totp_open_config_file(Storage* storage); void totp_close_config_file(FlipperFormat* file); -void totp_full_save_config_file(PluginState* const plugin_state); +void totp_full_save_config_file(const PluginState* const plugin_state); void totp_config_file_load_base(PluginState* const plugin_state); TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state); -void totp_config_file_save_new_token(TokenInfo* token_info); +void totp_config_file_save_new_token(const TokenInfo* token_info); void totp_config_file_update_timezone_offset(float new_timezone_offset); diff --git a/applications/plugins/totp/services/crypto/crypto.c b/applications/plugins/totp/services/crypto/crypto.c index ade2f9f49..79e41e6fd 100644 --- a/applications/plugins/totp/services/crypto/crypto.c +++ b/applications/plugins/totp/services/crypto/crypto.c @@ -3,6 +3,7 @@ #include #include "../config/config.h" #include "../../types/common.h" +#include "memset_s.h" #define CRYPTO_KEY_SLOT 2 #define CRYPTO_VERIFY_KEY "FFF_Crypto_pass" @@ -11,13 +12,13 @@ uint8_t* totp_crypto_encrypt( const uint8_t* plain_data, - const uint8_t plain_data_length, + const size_t plain_data_length, const uint8_t* iv, - uint8_t* encrypted_data_length) { + size_t* encrypted_data_length) { uint8_t* encrypted_data; size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR; if(remain) { - uint8_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR; + size_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR; uint8_t* plain_data_aligned = malloc(plain_data_aligned_length); memset(plain_data_aligned, 0, plain_data_aligned_length); memcpy(plain_data_aligned, plain_data, plain_data_length); @@ -29,7 +30,7 @@ uint8_t* totp_crypto_encrypt( furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length); furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT); - memset(plain_data_aligned, 0, plain_data_aligned_length); + memset_s(plain_data_aligned, sizeof(plain_data_aligned), 0, plain_data_aligned_length); free(plain_data_aligned); } else { encrypted_data = malloc(plain_data_length); @@ -45,9 +46,9 @@ uint8_t* totp_crypto_encrypt( uint8_t* totp_crypto_decrypt( const uint8_t* encrypted_data, - const uint8_t encrypted_data_length, + const size_t encrypted_data_length, const uint8_t* iv, - uint8_t* decrypted_data_length) { + size_t* decrypted_data_length) { *decrypted_data_length = encrypted_data_length; uint8_t* decrypted_data = malloc(*decrypted_data_length); furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv); @@ -56,7 +57,7 @@ uint8_t* totp_crypto_decrypt( return decrypted_data; } -void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length) { +void 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); @@ -118,8 +119,8 @@ void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_le } bool totp_crypto_verify_key(const PluginState* plugin_state) { - uint8_t decrypted_key_length; - uint8_t* decrypted_key = totp_crypto_decrypt( + size_t decrypted_key_length; + const uint8_t* decrypted_key = totp_crypto_decrypt( plugin_state->crypto_verify_data, plugin_state->crypto_verify_data_length, &plugin_state->iv[0], diff --git a/applications/plugins/totp/services/crypto/crypto.h b/applications/plugins/totp/services/crypto/crypto.h index 9fc319659..f0a28f798 100644 --- a/applications/plugins/totp/services/crypto/crypto.h +++ b/applications/plugins/totp/services/crypto/crypto.h @@ -4,13 +4,13 @@ uint8_t* totp_crypto_encrypt( const uint8_t* plain_data, - const uint8_t plain_data_length, + const size_t plain_data_length, const uint8_t* iv, - uint8_t* encrypted_data_length); + size_t* encrypted_data_length); uint8_t* totp_crypto_decrypt( const uint8_t* encrypted_data, - const uint8_t encrypted_data_length, + const size_t encrypted_data_length, const uint8_t* iv, - uint8_t* decrypted_data_length); -void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length); + size_t* decrypted_data_length); +void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length); bool totp_crypto_verify_key(const PluginState* plugin_state); \ No newline at end of file diff --git a/applications/plugins/totp/services/crypto/memset_s.c b/applications/plugins/totp/services/crypto/memset_s.c new file mode 100644 index 000000000..81c285c0d --- /dev/null +++ b/applications/plugins/totp/services/crypto/memset_s.c @@ -0,0 +1,22 @@ +#include "memset_s.h" + +#define RSIZE_MAX 0x7fffffffffffffffUL + +errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n) { + if(!s || smax > RSIZE_MAX) { + return EINVAL; + } + + errno_t violation_present = 0; + if(n > smax) { + n = smax; + violation_present = EINVAL; + } + + volatile unsigned char* v = s; + for(rsize_t i = 0u; i < n; ++i) { + *v++ = (unsigned char)c; + } + + return violation_present; +} \ No newline at end of file diff --git a/applications/plugins/totp/services/crypto/memset_s.h b/applications/plugins/totp/services/crypto/memset_s.h new file mode 100644 index 000000000..2889e23b2 --- /dev/null +++ b/applications/plugins/totp/services/crypto/memset_s.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +#ifndef _RSIZE_T_DECLARED +typedef uint64_t rsize_t; +#define _RSIZE_T_DECLARED +#endif +#ifndef _ERRNOT_DECLARED +typedef int16_t errno_t; +#define _ERRNOT_DECLARED +#endif + +errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n); \ No newline at end of file diff --git a/applications/plugins/totp/services/list/list.c b/applications/plugins/totp/services/list/list.c index 3a3317980..20d92e71b 100644 --- a/applications/plugins/totp/services/list/list.c +++ b/applications/plugins/totp/services/list/list.c @@ -26,7 +26,7 @@ ListNode* list_add(ListNode* head, void* data) { return head; } -ListNode* list_find(ListNode* head, void* data) { +ListNode* list_find(ListNode* head, const void* data) { ListNode* it; for(it = head; it != NULL; it = it->next) @@ -66,7 +66,8 @@ ListNode* list_remove(ListNode* head, ListNode* ep) { } void list_free(ListNode* head) { - ListNode *it = head, *tmp; + ListNode* it = head; + ListNode* tmp; while(it != NULL) { tmp = it; diff --git a/applications/plugins/totp/services/list/list.h b/applications/plugins/totp/services/list/list.h index 771eac565..93acb0f34 100644 --- a/applications/plugins/totp/services/list/list.h +++ b/applications/plugins/totp/services/list/list.h @@ -14,7 +14,7 @@ ListNode* list_add( void* data); /* adds element with specified data to the end of the list and returns new head node. */ ListNode* list_find( ListNode* head, - void* data); /* returns pointer of element with specified data in list. */ + const void* data); /* returns pointer of element with specified data in list. */ ListNode* list_element_at( ListNode* head, uint16_t index); /* returns pointer of element with specified index in list. */ @@ -22,3 +22,12 @@ ListNode* list_remove( ListNode* head, ListNode* ep); /* removes element from the list and returns new head node. */ void list_free(ListNode* head); /* deletes all elements of the list. */ + +#define TOTP_LIST_INIT_OR_ADD(head, item) \ + do { \ + if(head == NULL) { \ + head = list_init_head(item); \ + } else { \ + list_add(head, item); \ + } \ + } while(false) diff --git a/applications/plugins/totp/services/nullable/nullable.h b/applications/plugins/totp/services/nullable/nullable.h new file mode 100644 index 000000000..4f9b7bc01 --- /dev/null +++ b/applications/plugins/totp/services/nullable/nullable.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#define TOTP_NULLABLE_STRUCT(value_type) \ + typedef struct TotpNullable_##value_type { \ + bool is_null; \ + value_type value; \ + } TotpNullable_##value_type + +#define TOTP_NULLABLE_NULL(s) s.is_null = true +#define TOTP_NULLABLE_VALUE(s, v) \ + s.is_null = false; \ + s.value = v + +TOTP_NULLABLE_STRUCT(uint16_t); diff --git a/applications/plugins/totp/services/roll_value/roll_value.c b/applications/plugins/totp/services/roll_value/roll_value.c new file mode 100644 index 000000000..b8f30e078 --- /dev/null +++ b/applications/plugins/totp/services/roll_value/roll_value.c @@ -0,0 +1,28 @@ +#include "roll_value.h" + +#define TOTP_ROLL_VALUE_FN(type, step_type) \ + TOTP_ROLL_VALUE_FN_HEADER(type, step_type) { \ + type v = *value; \ + if(step > 0 && v > max - step) { \ + if(overflow_behavior == RollOverflowBehaviorRoll) { \ + v = min; \ + } else if(overflow_behavior == RollOverflowBehaviorStop) { \ + v = max; \ + } \ + } else if(step < 0 && v < min - step) { \ + if(overflow_behavior == RollOverflowBehaviorRoll) { \ + v = max; \ + } else if(overflow_behavior == RollOverflowBehaviorStop) { \ + v = min; \ + } \ + } else { \ + v += step; \ + } \ + *value = v; \ + } + +TOTP_ROLL_VALUE_FN(int8_t, int8_t) + +TOTP_ROLL_VALUE_FN(uint8_t, int8_t) + +TOTP_ROLL_VALUE_FN(uint16_t, int16_t); \ No newline at end of file diff --git a/applications/plugins/totp/services/roll_value/roll_value.h b/applications/plugins/totp/services/roll_value/roll_value.h new file mode 100644 index 000000000..87337597f --- /dev/null +++ b/applications/plugins/totp/services/roll_value/roll_value.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +typedef enum { RollOverflowBehaviorStop, RollOverflowBehaviorRoll } TotpRollValueOverflowBehavior; + +#define TOTP_ROLL_VALUE_FN_HEADER(type, step_type) \ + void totp_roll_value_##type( \ + type* value, \ + step_type step, \ + type min, \ + type max, \ + TotpRollValueOverflowBehavior overflow_behavior) + +TOTP_ROLL_VALUE_FN_HEADER(int8_t, int8_t); +TOTP_ROLL_VALUE_FN_HEADER(uint8_t, int8_t); +TOTP_ROLL_VALUE_FN_HEADER(uint16_t, int16_t); \ No newline at end of file diff --git a/applications/plugins/totp/services/totp/totp.c b/applications/plugins/totp/services/totp/totp.c index 90e49367d..68531e171 100644 --- a/applications/plugins/totp/services/totp/totp.c +++ b/applications/plugins/totp/services/totp/totp.c @@ -42,14 +42,14 @@ uint32_t otp_generate( TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, - uint8_t plain_secret_length, + size_t plain_secret_length, uint64_t input) { uint8_t* hmac = malloc(64); memset(hmac, 0, 64); uint64_t input_swapped = swap_uint64(input); - int hmac_len = (*(algo))(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, hmac); + int hmac_len = (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, hmac); if(hmac_len == 0) { free(hmac); return OTP_ERROR; @@ -80,7 +80,7 @@ uint32_t totp_at( TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, - uint8_t plain_secret_length, + size_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval) { @@ -96,9 +96,9 @@ uint32_t totp_at( static int totp_algo_sha1( const uint8_t* key, - uint8_t key_length, + size_t key_length, const uint8_t* input, - uint8_t input_length, + size_t input_length, uint8_t* output) { hmac_sha1(key, key_length, input, input_length, output); return HMAC_SHA1_RESULT_SIZE; @@ -106,9 +106,9 @@ static int totp_algo_sha1( static int totp_algo_sha256( const uint8_t* key, - uint8_t key_length, + size_t key_length, const uint8_t* input, - uint8_t input_length, + size_t input_length, uint8_t* output) { hmac_sha256(key, key_length, input, input_length, output); return HMAC_SHA256_RESULT_SIZE; @@ -116,9 +116,9 @@ static int totp_algo_sha256( static int totp_algo_sha512( const uint8_t* key, - uint8_t key_length, + size_t key_length, const uint8_t* input, - uint8_t input_length, + size_t input_length, uint8_t* output) { hmac_sha512(key, key_length, input, input_length, output); return HMAC_SHA512_RESULT_SIZE; diff --git a/applications/plugins/totp/services/totp/totp.h b/applications/plugins/totp/services/totp/totp.h index 31e70e01b..431ca11aa 100644 --- a/applications/plugins/totp/services/totp/totp.h +++ b/applications/plugins/totp/services/totp/totp.h @@ -17,9 +17,9 @@ */ typedef int (*TOTP_ALGO)( const uint8_t* key, - uint8_t key_length, + size_t key_length, const uint8_t* input, - uint8_t input_length, + size_t input_length, uint8_t* output); /* @@ -47,7 +47,7 @@ uint32_t totp_at( TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, - uint8_t plain_secret_length, + size_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval); diff --git a/applications/plugins/totp/services/ui/icons.h b/applications/plugins/totp/services/ui/icons.h deleted file mode 100644 index 2ce25a898..000000000 --- a/applications/plugins/totp/services/ui/icons.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -#define ICON_ARROW_LEFT_8x9_WIDTH 8 -#define ICON_ARROW_LEFT_8x9_HEIGHT 9 -static const uint8_t ICON_ARROW_LEFT_8x9[] = {0x80, 0xe0, 0xf8, 0xfe, 0xff, 0xfe, 0xf8, 0xe0, 0x80}; - -#define ICON_ARROW_RIGHT_8x9_WIDTH 8 -#define ICON_ARROW_RIGHT_8x9_HEIGHT 9 -static const uint8_t ICON_ARROW_RIGHT_8x9[] = - {0x01, 0x07, 0x1f, 0x7f, 0xff, 0x7f, 0x1f, 0x07, 0x01}; diff --git a/applications/plugins/totp/services/ui/ui_controls.c b/applications/plugins/totp/services/ui/ui_controls.c index 7f6a4dd4d..af029dd9f 100644 --- a/applications/plugins/totp/services/ui/ui_controls.c +++ b/applications/plugins/totp/services/ui/ui_controls.c @@ -1,11 +1,15 @@ #include "ui_controls.h" +#include #include "constants.h" -#include "icons.h" #define TEXT_BOX_HEIGHT 13 #define TEXT_BOX_MARGIN 4 -void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected) { +void ui_control_text_box_render( + Canvas* const canvas, + int16_t y, + const char* text, + bool is_selected) { if(y < -TEXT_BOX_HEIGHT) { return; } @@ -44,7 +48,7 @@ void ui_control_select_render( int16_t x, int16_t y, uint8_t width, - char* text, + const char* text, bool is_selected) { if(y < -TEXT_BOX_HEIGHT) { return; @@ -77,20 +81,10 @@ void ui_control_select_render( canvas_draw_str_aligned( canvas, x + (width >> 1), TEXT_BOX_MARGIN + 3 + y, AlignCenter, AlignTop, text); - canvas_draw_xbm( - canvas, - x + TEXT_BOX_MARGIN + 2, - TEXT_BOX_MARGIN + 2 + y, - ICON_ARROW_LEFT_8x9_WIDTH, - ICON_ARROW_LEFT_8x9_HEIGHT, - &ICON_ARROW_LEFT_8x9[0]); - canvas_draw_xbm( - canvas, - x + width - TEXT_BOX_MARGIN - 10, - TEXT_BOX_MARGIN + 2 + y, - ICON_ARROW_RIGHT_8x9_WIDTH, - ICON_ARROW_RIGHT_8x9_HEIGHT, - &ICON_ARROW_RIGHT_8x9[0]); + canvas_draw_icon( + canvas, x + TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 2 + y, &I_totp_arrow_left_8x9); + canvas_draw_icon( + canvas, x + width - TEXT_BOX_MARGIN - 10, TEXT_BOX_MARGIN + 2 + y, &I_totp_arrow_right_8x9); } void ui_control_button_render( @@ -99,7 +93,7 @@ void ui_control_button_render( int16_t y, uint8_t width, uint8_t height, - char* text, + const char* text, bool is_selected) { if(y < -height) { return; diff --git a/applications/plugins/totp/services/ui/ui_controls.h b/applications/plugins/totp/services/ui/ui_controls.h index e86b3e5d9..ef3af5f55 100644 --- a/applications/plugins/totp/services/ui/ui_controls.h +++ b/applications/plugins/totp/services/ui/ui_controls.h @@ -3,19 +3,23 @@ #include #include -void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected); +void ui_control_text_box_render( + Canvas* const canvas, + int16_t y, + const char* text, + bool is_selected); void ui_control_button_render( Canvas* const canvas, int16_t x, int16_t y, uint8_t width, uint8_t height, - char* text, + const char* text, bool is_selected); void ui_control_select_render( Canvas* const canvas, int16_t x, int16_t y, uint8_t width, - char* text, + const char* text, bool is_selected); diff --git a/applications/plugins/totp/totp_app.c b/applications/plugins/totp/totp_app.c index ede8416b6..3bc85e211 100644 --- a/applications/plugins/totp/totp_app.c +++ b/applications/plugins/totp/totp_app.c @@ -24,7 +24,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25); - if(plugin_state != NULL && !plugin_state->changing_scene) { + if (plugin_state != NULL && !plugin_state->changing_scene) { totp_scene_director_render(canvas, plugin_state); } @@ -49,43 +49,29 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { totp_scene_director_init_scenes(plugin_state); - if(plugin_state->crypto_verify_data == NULL) { + if (plugin_state->crypto_verify_data == NULL) { DialogMessage* message = dialog_message_alloc(); dialog_message_set_buttons(message, "No", NULL, "Yes"); - dialog_message_set_text( - message, - "Would you like to setup PIN?", - SCREEN_WIDTH_CENTER, - SCREEN_HEIGHT_CENTER, - AlignCenter, - AlignCenter); + dialog_message_set_text(message, "Would you like to setup PIN?", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message); dialog_message_free(message); - if(dialog_result == DialogMessageButtonRight) { + if (dialog_result == DialogMessageButtonRight) { totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); } else { totp_crypto_seed_iv(plugin_state, NULL, 0); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); } - } else if(plugin_state->pin_set) { + } 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_verify_key(plugin_state)) { + if (totp_crypto_verify_key(plugin_state)) { totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); } else { - FURI_LOG_E( - LOGGING_TAG, - "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other"); + FURI_LOG_E(LOGGING_TAG, "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other"); DialogMessage* message = dialog_message_alloc(); dialog_message_set_buttons(message, "Exit", NULL, NULL); - dialog_message_set_text( - message, - "Digital signature verification failed", - SCREEN_WIDTH_CENTER, - SCREEN_HEIGHT_CENTER, - AlignCenter, - AlignCenter); + dialog_message_set_text(message, "Digital signature verification failed", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); dialog_message_show(plugin_state->dialogs, message); dialog_message_free(message); return false; @@ -108,7 +94,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) { ListNode* node = plugin_state->tokens_list; ListNode* tmp; - while(node != NULL) { + while (node != NULL) { tmp = node->next; TokenInfo* tokenInfo = node->data; token_info_free(tokenInfo); @@ -116,7 +102,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) { node = tmp; } - if(plugin_state->crypto_verify_data != NULL) { + if (plugin_state->crypto_verify_data != NULL) { free(plugin_state->crypto_verify_data); } free(plugin_state); @@ -126,7 +112,7 @@ int32_t totp_app() { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); PluginState* plugin_state = malloc(sizeof(PluginState)); - if(!totp_plugin_state_init(plugin_state)) { + if (!totp_plugin_state_init(plugin_state)) { FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n"); totp_plugin_state_free(plugin_state); return 254; @@ -151,25 +137,23 @@ int32_t totp_app() { bool processing = true; uint32_t last_user_interaction_time = furi_get_tick(); while(processing) { - if(plugin_state->changing_scene) continue; + if (plugin_state->changing_scene) continue; FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - PluginState* plugin_state = acquire_mutex_block(&state_mutex); + PluginState* plugin_state_m = acquire_mutex_block(&state_mutex); if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { + if (event.type == EventTypeKey) { last_user_interaction_time = furi_get_tick(); } - processing = totp_scene_director_handle_event(&event, plugin_state); - } else if( - plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication && - furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { - totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); + 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) { + totp_scene_director_activate_scene(plugin_state_m, TotpSceneAuthentication, NULL); } view_port_update(view_port); - release_mutex(&state_mutex, plugin_state); + release_mutex(&state_mutex, plugin_state_m); } view_port_enabled_set(view_port, false); diff --git a/applications/plugins/totp/types/plugin_state.h b/applications/plugins/totp/types/plugin_state.h index 98afe53cf..9b16d7d57 100644 --- a/applications/plugins/totp/types/plugin_state.h +++ b/applications/plugins/totp/types/plugin_state.h @@ -19,10 +19,10 @@ typedef struct { float timezone_offset; ListNode* tokens_list; bool token_list_loaded; - uint8_t tokens_count; + uint16_t tokens_count; uint8_t* crypto_verify_data; - uint8_t crypto_verify_data_length; + size_t crypto_verify_data_length; bool pin_set; uint8_t iv[TOTP_IV_SIZE]; uint8_t base_iv[TOTP_IV_SIZE]; diff --git a/applications/plugins/totp/types/token_info.c b/applications/plugins/totp/types/token_info.c index 09ad1230a..17b2af9aa 100644 --- a/applications/plugins/totp/types/token_info.c +++ b/applications/plugins/totp/types/token_info.c @@ -5,6 +5,7 @@ #include "common.h" #include "../services/base32/base32.h" #include "../services/crypto/crypto.h" +#include "../services/crypto/memset_s.h" TokenInfo* token_info_alloc() { TokenInfo* tokenInfo = malloc(sizeof(TokenInfo)); @@ -23,11 +24,11 @@ void token_info_free(TokenInfo* token_info) { bool token_info_set_secret( TokenInfo* token_info, const char* base32_token_secret, - uint8_t token_secret_length, - uint8_t* iv) { + size_t token_secret_length, + const uint8_t* iv) { uint8_t* plain_secret = malloc(token_secret_length); int plain_secret_length = - base32_decode((uint8_t*)base32_token_secret, plain_secret, token_secret_length); + base32_decode((const uint8_t*)base32_token_secret, plain_secret, token_secret_length); bool result; if(plain_secret_length >= 0) { token_info->token = @@ -37,12 +38,12 @@ bool token_info_set_secret( result = false; } - memset(plain_secret, 0, token_secret_length); + memset_s(plain_secret, sizeof(plain_secret), 0, token_secret_length); free(plain_secret); return result; } -uint8_t token_info_get_digits_count(TokenInfo* token_info) { +uint8_t token_info_get_digits_count(const TokenInfo* token_info) { switch(token_info->digits) { case TOTP_6_DIGITS: return 6; diff --git a/applications/plugins/totp/types/token_info.h b/applications/plugins/totp/types/token_info.h index e40c6e9bf..4f1223367 100644 --- a/applications/plugins/totp/types/token_info.h +++ b/applications/plugins/totp/types/token_info.h @@ -8,7 +8,7 @@ typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount; typedef struct { uint8_t* token; - uint8_t token_length; + size_t token_length; char* name; TokenHashAlgo algo; TokenDigitsCount digits; @@ -19,6 +19,6 @@ void token_info_free(TokenInfo* token_info); bool token_info_set_secret( TokenInfo* token_info, const char* base32_token_secret, - uint8_t token_secret_length, - uint8_t* iv); -uint8_t token_info_get_digits_count(TokenInfo* token_info); + size_t token_secret_length, + const uint8_t* iv); +uint8_t token_info_get_digits_count(const TokenInfo* token_info);