diff --git a/applications/external/totp/application.fam b/applications/external/totp/application.fam index 600ed6ca3..3c7ba149e 100644 --- a/applications/external/totp/application.fam +++ b/applications/external/totp/application.fam @@ -9,10 +9,14 @@ App( "dialogs", "storage", "input", - "notification" + "notification", + "bt" ], stack_size=2 * 1024, order=20, + fap_author="Alexander Kopachov (@akopachov)", + fap_description="Software-based TOTP authenticator for Flipper Zero device", + fap_weburl="https://github.com/akopachov/flipper-zero_authenticator", fap_category="Misc", fap_icon_assets="images", fap_icon="totp_10px.png", diff --git a/applications/external/totp/cli/cli.c b/applications/external/totp/cli/cli.c index 28d173766..ce2530804 100644 --- a/applications/external/totp/cli/cli.c +++ b/applications/external/totp/cli/cli.c @@ -12,6 +12,7 @@ #include "commands/pin/pin.h" #include "commands/notification/notification.h" #include "commands/reset/reset.h" +#include "commands/automation/automation.h" static void totp_cli_print_unknown_command(const FuriString* unknown_command) { TOTP_CLI_PRINTF_ERROR( @@ -57,6 +58,8 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { totp_cli_command_pin_handle(plugin_state, args, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_NOTIFICATION) == 0) { totp_cli_command_notification_handle(plugin_state, args, cli); + } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) { + totp_cli_command_automation_handle(plugin_state, args, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) { totp_cli_command_reset_handle(cli, cli_context->event_queue); } else { diff --git a/applications/external/totp/cli/commands/add/add.c b/applications/external/totp/cli/commands/add/add.c index fbcd58530..91f9256b2 100644 --- a/applications/external/totp/cli/commands/add/add.c +++ b/applications/external/totp/cli/commands/add/add.c @@ -62,7 +62,7 @@ void totp_cli_command_add_docopt_usage() { } void totp_cli_command_add_docopt_arguments() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD_ARG_NAME " Token name\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD_ARG_NAME " Token name\r\n"); } void totp_cli_command_add_docopt_options() { diff --git a/applications/external/totp/cli/commands/automation/automation.c b/applications/external/totp/cli/commands/automation/automation.c new file mode 100644 index 000000000..1fd87f456 --- /dev/null +++ b/applications/external/totp/cli/commands/automation/automation.c @@ -0,0 +1,133 @@ +#include "automation.h" +#include +#include "../../../services/config/config.h" +#include "../../../ui/scene_director.h" +#include "../../cli_helpers.h" + +#define TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD "automation" +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "none" +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "usb" +#ifdef TOTP_BADBT_TYPE_ENABLED +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt" +#endif + +void totp_cli_command_automation_docopt_commands() { + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation method\r\n"); +} + +void totp_cli_command_automation_docopt_usage() { + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL( + DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n"); +} + +void totp_cli_command_automation_docopt_arguments() { + TOTP_CLI_PRINTF( + " " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD + " Automation method to be set. Must be one of [" TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE + ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB +#ifdef TOTP_BADBT_TYPE_ENABLED + ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT +#endif + "]\r\n"); +} + +static void totp_cli_command_automation_print_method(AutomationMethod method, char* color) { +#ifdef TOTP_BADBT_TYPE_ENABLED + bool has_previous_method = false; +#endif + if(method & AutomationMethodBadUsb) { + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "\""); +#ifdef TOTP_BADBT_TYPE_ENABLED + has_previous_method = true; +#endif + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + if(method & AutomationMethodBadBt) { + if(has_previous_method) { + TOTP_CLI_PRINTF_COLORFUL(color, " and "); + } + + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "\""); + } +#endif + + if(method == AutomationMethodNone) { + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "\""); + } +} + +void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { + if(!totp_cli_ensure_authenticated(plugin_state, cli)) { + return; + } + + FuriString* temp_str = furi_string_alloc(); + bool new_method_provided = false; + AutomationMethod new_method = AutomationMethodNone; + bool args_valid = true; + while(args_read_string_and_trim(args, temp_str)) { + if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) { + new_method_provided = true; + new_method = AutomationMethodNone; + } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB) == 0) { + new_method_provided = true; + new_method |= AutomationMethodBadUsb; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT) == 0) { + new_method_provided = true; + new_method |= AutomationMethodBadBt; + } +#endif + else { + args_valid = false; + break; + } + } + + do { + if(!args_valid) { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + break; + } + + if(new_method_provided) { + Scene previous_scene = TotpSceneNone; + if(plugin_state->current_scene == TotpSceneGenerateToken || + plugin_state->current_scene == TotpSceneAppSettings) { + previous_scene = plugin_state->current_scene; + totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); + } + + plugin_state->automation_method = new_method; + if(totp_config_file_update_automation_method(new_method) == + TotpConfigFileUpdateSuccess) { + TOTP_CLI_PRINTF_SUCCESS("Automation method is set to "); + totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS); + cli_nl(); + } else { + TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + if(!(new_method & AutomationMethodBadBt) && + plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + + if(previous_scene != TotpSceneNone) { + totp_scene_director_activate_scene(plugin_state, previous_scene, NULL); + } + } else { + TOTP_CLI_PRINTF_INFO("Current automation method is "); + totp_cli_command_automation_print_method( + plugin_state->automation_method, TOTP_CLI_COLOR_INFO); + cli_nl(); + } + } while(false); + + furi_string_free(temp_str); +} \ No newline at end of file diff --git a/applications/external/totp/cli/commands/automation/automation.h b/applications/external/totp/cli/commands/automation/automation.h new file mode 100644 index 000000000..fb62e638e --- /dev/null +++ b/applications/external/totp/cli/commands/automation/automation.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include "../../../types/plugin_state.h" + +#define TOTP_CLI_COMMAND_AUTOMATION "automation" + +void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli); +void totp_cli_command_automation_docopt_commands(); +void totp_cli_command_automation_docopt_usage(); +void totp_cli_command_automation_docopt_arguments(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/delete/delete.c b/applications/external/totp/cli/commands/delete/delete.c index 8fe72e220..04cc815a4 100644 --- a/applications/external/totp/cli/commands/delete/delete.c +++ b/applications/external/totp/cli/commands/delete/delete.c @@ -24,7 +24,7 @@ void totp_cli_command_delete_docopt_usage() { } void totp_cli_command_delete_docopt_arguments() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE_ARG_INDEX " Token index in the list\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE_ARG_INDEX " Token index in the list\r\n"); } void totp_cli_command_delete_docopt_options() { diff --git a/applications/external/totp/cli/commands/help/help.c b/applications/external/totp/cli/commands/help/help.c index 104b39e47..34b44debd 100644 --- a/applications/external/totp/cli/commands/help/help.c +++ b/applications/external/totp/cli/commands/help/help.c @@ -8,6 +8,7 @@ #include "../pin/pin.h" #include "../notification/notification.h" #include "../reset/reset.h" +#include "../automation/automation.h" void totp_cli_command_help_docopt_commands() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT @@ -31,6 +32,7 @@ void totp_cli_command_help_handle() { totp_cli_command_pin_docopt_usage(); totp_cli_command_notification_docopt_usage(); totp_cli_command_reset_docopt_usage(); + totp_cli_command_automation_docopt_usage(); cli_nl(); TOTP_CLI_PRINTF("Commands:\r\n"); totp_cli_command_help_docopt_commands(); @@ -42,12 +44,14 @@ void totp_cli_command_help_handle() { totp_cli_command_pin_docopt_commands(); totp_cli_command_notification_docopt_commands(); totp_cli_command_reset_docopt_commands(); + totp_cli_command_automation_docopt_commands(); cli_nl(); TOTP_CLI_PRINTF("Arguments:\r\n"); totp_cli_command_add_docopt_arguments(); totp_cli_command_delete_docopt_arguments(); totp_cli_command_timezone_docopt_arguments(); totp_cli_command_notification_docopt_arguments(); + totp_cli_command_automation_docopt_arguments(); cli_nl(); TOTP_CLI_PRINTF("Options:\r\n"); totp_cli_command_add_docopt_options(); diff --git a/applications/external/totp/cli/commands/notification/notification.c b/applications/external/totp/cli/commands/notification/notification.c index bbbd52703..016b83d0d 100644 --- a/applications/external/totp/cli/commands/notification/notification.c +++ b/applications/external/totp/cli/commands/notification/notification.c @@ -4,7 +4,7 @@ #include "../../../ui/scene_director.h" #include "../../cli_helpers.h" -#define TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD "method" +#define TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD "notification" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE "none" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "sound" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "vibro" @@ -23,7 +23,7 @@ void totp_cli_command_notification_docopt_usage() { void totp_cli_command_notification_docopt_arguments() { TOTP_CLI_PRINTF( " " TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD - " Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE + " Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "]\r\n"); } diff --git a/applications/external/totp/cli/commands/timezone/timezone.c b/applications/external/totp/cli/commands/timezone/timezone.c index 9eb0cb5f6..265d80e53 100644 --- a/applications/external/totp/cli/commands/timezone/timezone.c +++ b/applications/external/totp/cli/commands/timezone/timezone.c @@ -20,7 +20,7 @@ void totp_cli_command_timezone_docopt_usage() { void totp_cli_command_timezone_docopt_arguments() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE - " Timezone offset in hours to be set\r\n"); + " Timezone offset in hours to be set\r\n"); } void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h new file mode 100644 index 000000000..d3b30aee0 --- /dev/null +++ b/applications/external/totp/features_config.h @@ -0,0 +1,2 @@ +#define TOTP_BADBT_TYPE_ENABLED +#define TOTP_BADBT_TYPE_ICON_ENABLED \ No newline at end of file diff --git a/applications/external/totp/images/hid_ble_10x7.png b/applications/external/totp/images/hid_ble_10x7.png new file mode 100644 index 000000000..3cd1ff95c Binary files /dev/null and b/applications/external/totp/images/hid_ble_10x7.png differ diff --git a/applications/external/totp/services/config/config.c b/applications/external/totp/services/config/config.c index 034ed925e..66c07ebfa 100644 --- a/applications/external/totp/services/config/config.c +++ b/applications/external/totp/services/config/config.c @@ -4,6 +4,7 @@ #include "../list/list.h" #include "../../types/common.h" #include "../../types/token_info.h" +#include "../../features_config.h" #include "migrations/config_migration_v1_to_v2.h" #include "migrations/config_migration_v2_to_v3.h" @@ -136,6 +137,14 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1); + tmp_uint32 = AutomationMethodBadUsb; + flipper_format_write_comment_cstr(fff_data_file, " "); + flipper_format_write_comment_cstr( + fff_data_file, + "Automation method (0 - None, 1 - BadUSB, 2 - BadBT, 3 - BadUSB and BadBT)"); + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1); + FuriString* temp_str = furi_string_alloc(); flipper_format_write_comment_cstr(fff_data_file, " "); @@ -329,6 +338,33 @@ TotpConfigFileUpdateResult return update_result; } +TotpConfigFileUpdateResult + totp_config_file_update_automation_method(AutomationMethod new_automation_method) { + Storage* cfg_storage = totp_open_storage(); + FlipperFormat* file; + TotpConfigFileUpdateResult update_result; + + if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) { + do { + uint32_t tmp_uint32 = new_automation_method; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + update_result = TotpConfigFileUpdateError; + break; + } + + update_result = TotpConfigFileUpdateSuccess; + } while(false); + + totp_close_config_file(file); + } else { + update_result = TotpConfigFileUpdateError; + } + + totp_close_storage(); + return update_result; +} + TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginState* plugin_state) { Storage* cfg_storage = totp_open_storage(); FlipperFormat* file; @@ -347,6 +383,13 @@ TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginSta break; } + tmp_uint32 = plugin_state->automation_method; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + update_result = TotpConfigFileUpdateError; + break; + } + update_result = TotpConfigFileUpdateSuccess; } while(false); @@ -409,6 +452,13 @@ TotpConfigFileUpdateResult totp_full_save_config_file(const PluginState* const p break; } + tmp_uint32 = plugin_state->automation_method; + if(!flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_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; @@ -594,6 +644,15 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st } plugin_state->notification_method = tmp_uint32; + + flipper_format_rewind(fff_data_file); + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + tmp_uint32 = AutomationMethodBadUsb; + } + + plugin_state->automation_method = tmp_uint32; } while(false); furi_string_free(temp_str); diff --git a/applications/external/totp/services/config/config.h b/applications/external/totp/services/config/config.h index c630810a6..3d325368d 100644 --- a/applications/external/totp/services/config/config.h +++ b/applications/external/totp/services/config/config.h @@ -103,6 +103,14 @@ TotpConfigFileUpdateResult totp_config_file_update_timezone_offset(float new_tim TotpConfigFileUpdateResult totp_config_file_update_notification_method(NotificationMethod new_notification_method); +/** + * @brief Updates automation method in an application config file + * @param new_automation_method new automation method to be set + * @return Config file update result + */ +TotpConfigFileUpdateResult + totp_config_file_update_automation_method(AutomationMethod new_automation_method); + /** * @brief Updates application user settings * @param plugin_state application state diff --git a/applications/external/totp/services/config/constants.h b/applications/external/totp/services/config/constants.h index 487fb159e..526179f41 100644 --- a/applications/external/totp/services/config/constants.h +++ b/applications/external/totp/services/config/constants.h @@ -13,6 +13,7 @@ #define TOTP_CONFIG_KEY_BASE_IV "BaseIV" #define TOTP_CONFIG_KEY_PINSET "PinIsSet" #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod" +#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod" #define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1" #define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256" diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index 966c9fb34..74ec52f2c 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -8,6 +8,7 @@ #include #include #include +#include "features_config.h" #include "services/config/config.h" #include "types/plugin_state.h" #include "types/token_info.h" @@ -108,6 +109,14 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { return false; } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->automation_method & AutomationMethodBadBt) { + plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init(); + } else { + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + return true; } @@ -130,6 +139,13 @@ static void totp_plugin_state_free(PluginState* plugin_state) { free(plugin_state->crypto_verify_data); } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + furi_mutex_free(plugin_state->mutex); free(plugin_state); } diff --git a/applications/external/totp/types/automation_method.h b/applications/external/totp/types/automation_method.h new file mode 100644 index 000000000..b51e59e03 --- /dev/null +++ b/applications/external/totp/types/automation_method.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../features_config.h" + +typedef uint8_t AutomationMethod; + +enum AutomationMethods { + AutomationMethodNone = 0b00, + AutomationMethodBadUsb = 0b01, +#ifdef TOTP_BADBT_TYPE_ENABLED + AutomationMethodBadBt = 0b10, +#endif +}; diff --git a/applications/external/totp/types/plugin_state.h b/applications/external/totp/types/plugin_state.h index dee500305..59a218ce3 100644 --- a/applications/external/totp/types/plugin_state.h +++ b/applications/external/totp/types/plugin_state.h @@ -3,9 +3,14 @@ #include #include #include +#include "../features_config.h" #include "../lib/list/list.h" #include "../ui/totp_scenes_enum.h" #include "notification_method.h" +#include "automation_method.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../workers/bt_type_code/bt_type_code.h" +#endif #define TOTP_IV_SIZE 16 @@ -92,4 +97,16 @@ typedef struct { * @brief Main rendering loop mutex */ FuriMutex* mutex; + + /** + * @brief Automation method + */ + AutomationMethod automation_method; + +#ifdef TOTP_BADBT_TYPE_ENABLED + /** + * @brief Bad-Bluetooth worker context + */ + TotpBtTypeCodeWorkerContext* bt_type_code_worker_context; +#endif } PluginState; diff --git a/applications/external/totp/ui/scene_director.c b/applications/external/totp/ui/scene_director.c index fcc9f37d8..c77e88ab4 100644 --- a/applications/external/totp/ui/scene_director.c +++ b/applications/external/totp/ui/scene_director.c @@ -37,7 +37,9 @@ void totp_scene_director_activate_scene( } void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) { - switch(plugin_state->current_scene) { + Scene current_scene = plugin_state->current_scene; + plugin_state->current_scene = TotpSceneNone; + switch(current_scene) { case TotpSceneGenerateToken: totp_scene_generate_token_deactivate(plugin_state); break; diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index b8936f395..1671542b8 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -10,16 +10,35 @@ #include "../../../services/convert/convert.h" #include "../../../lib/roll_value/roll_value.h" #include "../../../types/nullable.h" +#include "../../../features_config.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../../../workers/bt_type_code/bt_type_code.h" +#endif char* YES_NO_LIST[] = {"NO", "YES"}; +char* ON_OFF_LIST[] = {"OFF", "ON"}; -typedef enum { HoursInput, MinutesInput, Sound, Vibro, ConfirmButton } Control; +typedef enum { + HoursInput, + MinutesInput, + Sound, + Vibro, + BadUsb, +#ifdef TOTP_BADBT_TYPE_ENABLED + BadBt, +#endif + ConfirmButton +} Control; typedef struct { int8_t tz_offset_hours; uint8_t tz_offset_minutes; bool notification_sound; bool notification_vibro; + bool badusb_enabled; +#ifdef TOTP_BADBT_TYPE_ENABLED + bool badbt_enabled; +#endif uint8_t y_offset; TotpNullable_uint16_t current_token_index; Control selected_control; @@ -47,6 +66,10 @@ void totp_scene_app_settings_activate( scene_state->tz_offset_minutes = 60.0f * off_dec; scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound; scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro; + scene_state->badusb_enabled = plugin_state->automation_method & AutomationMethodBadUsb; +#ifdef TOTP_BADBT_TYPE_ENABLED + scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt; +#endif } static void two_digit_to_str(int8_t num, char* str) { @@ -73,7 +96,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu char tmp_str[4]; two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]); - canvas_draw_str_aligned(canvas, 0, 16 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); + canvas_draw_str_aligned(canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); ui_control_select_render( canvas, 36, @@ -84,7 +107,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]); canvas_draw_str_aligned( - canvas, 0, 34 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); + canvas, 0, 35 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); ui_control_select_render( canvas, 36, @@ -104,7 +127,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 0, 80 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); + canvas_draw_str_aligned(canvas, 0, 81 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); ui_control_select_render( canvas, 36, @@ -113,7 +136,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu YES_NO_LIST[scene_state->notification_sound], scene_state->selected_control == Sound); - canvas_draw_str_aligned(canvas, 0, 98 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); + canvas_draw_str_aligned(canvas, 0, 99 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); ui_control_select_render( canvas, 36, @@ -122,10 +145,43 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu YES_NO_LIST[scene_state->notification_vibro], scene_state->selected_control == Vibro); + canvas_draw_icon( + canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Automation"); + canvas_set_font(canvas, FontSecondary); + + canvas_draw_str_aligned( + canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:"); + ui_control_select_render( + canvas, + 36, + 138 - scene_state->y_offset, + SCREEN_WIDTH - 36, + ON_OFF_LIST[scene_state->badusb_enabled], + scene_state->selected_control == BadUsb); + +#ifdef TOTP_BADBT_TYPE_ENABLED + canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:"); + ui_control_select_render( + canvas, + 36, + 156 - scene_state->y_offset, + SCREEN_WIDTH - 36, + ON_OFF_LIST[scene_state->badbt_enabled], + scene_state->selected_control == BadBt); +#endif + ui_control_button_render( canvas, SCREEN_WIDTH_CENTER - 24, - 115 - scene_state->y_offset, +#ifdef TOTP_BADBT_TYPE_ENABLED + 178 - scene_state->y_offset, +#else + 165 - scene_state->y_offset, +#endif 48, 13, "Confirm", @@ -152,7 +208,9 @@ bool totp_scene_app_settings_handle_event( HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > MinutesInput) { + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; } else { scene_state->y_offset = 0; @@ -161,7 +219,9 @@ bool totp_scene_app_settings_handle_event( case InputKeyDown: totp_roll_value_uint8_t( &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > MinutesInput) { + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; } else { scene_state->y_offset = 0; @@ -178,7 +238,14 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == Vibro) { scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; + } +#endif break; case InputKeyLeft: if(scene_state->selected_control == HoursInput) { @@ -191,7 +258,14 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == Vibro) { scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; + } +#endif break; case InputKeyOk: if(scene_state->selected_control == ConfirmButton) { @@ -204,12 +278,26 @@ bool totp_scene_app_settings_handle_event( (scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone); + plugin_state->automation_method = + scene_state->badusb_enabled ? AutomationMethodBadUsb : AutomationMethodNone; +#ifdef TOTP_BADBT_TYPE_ENABLED + plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : + AutomationMethodNone; +#endif + if(totp_config_file_update_user_settings(plugin_state) != TotpConfigFileUpdateSuccess) { totp_dialogs_config_updating_error(plugin_state); return false; } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + if(!scene_state->current_token_index.is_null) { TokenMenuSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index.value}; diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index a882ae78c..9e8b21d09 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -14,7 +14,11 @@ #include "../../../lib/roll_value/roll_value.h" #include "../../scene_director.h" #include "../token_menu/totp_scene_token_menu.h" -#include "../../../workers/type_code/type_code.h" +#include "../../../features_config.h" +#include "../../../workers/usb_type_code/usb_type_code.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../../../workers/bt_type_code/bt_type_code.h" +#endif static const uint8_t PROGRESS_BAR_MARGIN = 3; static const uint8_t PROGRESS_BAR_HEIGHT = 4; @@ -25,9 +29,10 @@ typedef struct { bool need_token_update; TokenInfo* current_token; uint32_t last_token_gen_time; - TotpTypeCodeWorkerContext* type_code_worker_context; + TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context; NotificationMessage const** notification_sequence_new_token; NotificationMessage const** notification_sequence_badusb; + FuriMutex* last_code_update_sync; } SceneState; static const NotificationSequence* @@ -72,7 +77,7 @@ static const NotificationSequence* } static const NotificationSequence* - get_notification_sequence_badusb(const PluginState* plugin_state, SceneState* scene_state) { + get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) { if(scene_state->notification_sequence_badusb == NULL) { uint8_t i = 0; uint8_t length = 3; @@ -201,9 +206,28 @@ void totp_scene_generate_token_activate( plugin_state->current_scene_state = scene_state; FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset); update_totp_params(plugin_state); - scene_state->type_code_worker_context = totp_type_code_worker_start(); - scene_state->type_code_worker_context->string = &scene_state->last_code[0]; - scene_state->type_code_worker_context->string_length = TOTP_TOKEN_DIGITS_MAX_COUNT + 1; + + scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal); + if(plugin_state->automation_method & AutomationMethodBadUsb) { + scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start( + &scene_state->last_code[0], + TOTP_TOKEN_DIGITS_MAX_COUNT + 1, + scene_state->last_code_update_sync); + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + + if(plugin_state->automation_method & AutomationMethodBadBt) { + if(plugin_state->bt_type_code_worker_context == NULL) { + plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init(); + } + totp_bt_type_code_worker_start( + plugin_state->bt_type_code_worker_context, + &scene_state->last_code[0], + TOTP_TOKEN_DIGITS_MAX_COUNT + 1, + scene_state->last_code_update_sync); + } +#endif } void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) { @@ -242,8 +266,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ const TokenInfo* tokenInfo = scene_state->current_token; if(tokenInfo->token != NULL && tokenInfo->token_length > 0) { - furi_mutex_acquire( - scene_state->type_code_worker_context->string_sync, FuriWaitForever); + furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); size_t key_length; uint8_t* key = totp_crypto_decrypt( tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); @@ -262,12 +285,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ memset_s(key, key_length, 0, key_length); free(key); } else { - furi_mutex_acquire( - scene_state->type_code_worker_context->string_sync, FuriWaitForever); + furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); int_token_to_str(0, scene_state->last_code, tokenInfo->digits); } - furi_mutex_release(scene_state->type_code_worker_context->string_sync); + furi_mutex_release(scene_state->last_code_update_sync); if(is_new_token_time) { notification_message( @@ -327,6 +349,15 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ canvas_draw_icon( canvas, SCREEN_WIDTH - 9, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9); } + +#if defined(TOTP_BADBT_TYPE_ENABLED) && defined(TOTP_BADBT_TYPE_ICON_ENABLED) + if(plugin_state->automation_method & AutomationMethodBadBt && + plugin_state->bt_type_code_worker_context != NULL && + plugin_state->bt_type_code_worker_context->is_advertising) { + canvas_draw_icon( + canvas, SCREEN_WIDTH_CENTER - 5, SCREEN_HEIGHT_CENTER + 13, &I_hid_ble_10x7); + } +#endif } bool totp_scene_generate_token_handle_event( @@ -341,14 +372,27 @@ bool totp_scene_generate_token_handle_event( } SceneState* scene_state; - if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) { - scene_state = (SceneState*)plugin_state->current_scene_state; - totp_type_code_worker_notify( - scene_state->type_code_worker_context, TotpTypeCodeWorkerEventType); - notification_message( - plugin_state->notification_app, - get_notification_sequence_badusb(plugin_state, scene_state)); - return true; + if(event->input.type == InputTypeLong) { + if(event->input.key == InputKeyDown && plugin_state->automation_method & AutomationMethodBadUsb) { + scene_state = (SceneState*)plugin_state->current_scene_state; + totp_usb_type_code_worker_notify( + scene_state->usb_type_code_worker_context, TotpUsbTypeCodeWorkerEventType); + notification_message( + plugin_state->notification_app, + get_notification_sequence_automation(plugin_state, scene_state)); + return true; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(event->input.key == InputKeyUp && plugin_state->automation_method & AutomationMethodBadBt) { + scene_state = (SceneState*)plugin_state->current_scene_state; + totp_bt_type_code_worker_notify( + plugin_state->bt_type_code_worker_context, TotpBtTypeCodeWorkerEventType); + notification_message( + plugin_state->notification_app, + get_notification_sequence_automation(plugin_state, scene_state)); + return true; + } +#endif } if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { @@ -400,7 +444,14 @@ 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; - totp_type_code_worker_stop(scene_state->type_code_worker_context); + if(plugin_state->automation_method & AutomationMethodBadUsb) { + totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context); + } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->automation_method & AutomationMethodBadBt) { + totp_bt_type_code_worker_stop(plugin_state->bt_type_code_worker_context); + } +#endif if(scene_state->notification_sequence_new_token != NULL) { free(scene_state->notification_sequence_new_token); @@ -410,6 +461,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { free(scene_state->notification_sequence_badusb); } + furi_mutex_free(scene_state->last_code_update_sync); + free(scene_state); plugin_state->current_scene_state = NULL; } diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.c b/applications/external/totp/workers/bt_type_code/bt_type_code.c new file mode 100644 index 000000000..8b9cf6548 --- /dev/null +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.c @@ -0,0 +1,141 @@ +#include "bt_type_code.h" +#include +#include +#include "../../types/common.h" +#include "../../services/convert/convert.h" +#include "../constants.h" + +#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys") + +static inline bool totp_type_code_worker_stop_requested() { + return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop; +} + +static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context) { + uint8_t i = 0; + do { + furi_delay_ms(500); + i++; + } while(!furi_hal_bt_is_active() && i < 100 && !totp_type_code_worker_stop_requested()); + + if(furi_hal_bt_is_active() && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + furi_delay_ms(500); + i = 0; + while(i < context->string_length && context->string[i] != 0) { + uint8_t digit = CONVERT_CHAR_TO_DIGIT(context->string[i]); + if(digit > 9) break; + uint8_t hid_kb_key = hid_number_keys[digit]; + furi_hal_bt_hid_kb_press(hid_kb_key); + furi_delay_ms(30); + furi_hal_bt_hid_kb_release(hid_kb_key); + i++; + } + + furi_mutex_release(context->string_sync); + } +} + +static int32_t totp_type_code_worker_callback(void* context) { + furi_assert(context); + FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(context_mutex == NULL) { + return 251; + } + + TotpBtTypeCodeWorkerContext* bt_context = context; + + furi_hal_bt_start_advertising(); + bt_context->is_advertising = true; + + while(true) { + uint32_t flags = furi_thread_flags_wait( + TotpBtTypeCodeWorkerEventStop | TotpBtTypeCodeWorkerEventType, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); //-V562 + if(flags & TotpBtTypeCodeWorkerEventStop) break; + + if(furi_mutex_acquire(context_mutex, FuriWaitForever) == FuriStatusOk) { + if(flags & TotpBtTypeCodeWorkerEventType) { + totp_type_code_worker_type_code(bt_context); + } + + furi_mutex_release(context_mutex); + } + } + + furi_hal_bt_stop_advertising(); + + bt_context->is_advertising = false; + + furi_mutex_free(context_mutex); + + return 0; +} + +void totp_bt_type_code_worker_start( + TotpBtTypeCodeWorkerContext* context, + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync) { + furi_assert(context != NULL); + context->string = code_buf; + context->string_length = code_buf_length; + context->string_sync = code_buf_update_sync; + context->thread = furi_thread_alloc(); + furi_thread_set_name(context->thread, "TOTPBtHidWorker"); + furi_thread_set_stack_size(context->thread, 1024); + furi_thread_set_context(context->thread, context); + furi_thread_set_callback(context->thread, totp_type_code_worker_callback); + furi_thread_start(context->thread); +} + +void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context) { + furi_assert(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpBtTypeCodeWorkerEventStop); + furi_thread_join(context->thread); + furi_thread_free(context->thread); + context->thread = NULL; +} + +void totp_bt_type_code_worker_notify( + TotpBtTypeCodeWorkerContext* context, + TotpBtTypeCodeWorkerEvent event) { + furi_assert(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), event); +} + +TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { + TotpBtTypeCodeWorkerContext* context = malloc(sizeof(TotpBtTypeCodeWorkerContext)); + furi_check(context != NULL); + + context->bt = furi_record_open(RECORD_BT); + context->is_advertising = false; + bt_disconnect(context->bt); + furi_delay_ms(200); + bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH); + if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) { + FURI_LOG_E(LOGGING_TAG, "Failed to switch BT to keyboard HID profile"); + } + + return context; +} + +void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) { + furi_assert(context != NULL); + + if(context->thread != NULL) { + totp_bt_type_code_worker_stop(context); + } + + bt_disconnect(context->bt); + bt_keys_storage_set_default_path(context->bt); + + if(!bt_set_profile(context->bt, BtProfileSerial)) { + FURI_LOG_E(LOGGING_TAG, "Failed to switch BT to Serial profile"); + } + furi_record_close(RECORD_BT); + context->bt = NULL; + + free(context); +} \ No newline at end of file diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.h b/applications/external/totp/workers/bt_type_code/bt_type_code.h new file mode 100644 index 000000000..475b66db4 --- /dev/null +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +typedef uint8_t TotpBtTypeCodeWorkerEvent; + +typedef struct { + char* string; + uint8_t string_length; + FuriThread* thread; + FuriMutex* string_sync; + Bt* bt; + bool is_advertising; +} TotpBtTypeCodeWorkerContext; + +enum TotpBtTypeCodeWorkerEvents { + TotpBtTypeCodeWorkerEventReserved = (1 << 0), + TotpBtTypeCodeWorkerEventStop = (1 << 1), + TotpBtTypeCodeWorkerEventType = (1 << 2) +}; + +TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init(); +void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context); +void totp_bt_type_code_worker_start( + TotpBtTypeCodeWorkerContext* context, + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync); +void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context); +void totp_bt_type_code_worker_notify( + TotpBtTypeCodeWorkerContext* context, + TotpBtTypeCodeWorkerEvent event); \ No newline at end of file diff --git a/applications/external/totp/workers/constants.c b/applications/external/totp/workers/constants.c new file mode 100644 index 000000000..f3c103578 --- /dev/null +++ b/applications/external/totp/workers/constants.c @@ -0,0 +1,14 @@ +#include "constants.h" +#include + +const uint8_t hid_number_keys[10] = { + HID_KEYBOARD_0, + HID_KEYBOARD_1, + HID_KEYBOARD_2, + HID_KEYBOARD_3, + HID_KEYBOARD_4, + HID_KEYBOARD_5, + HID_KEYBOARD_6, + HID_KEYBOARD_7, + HID_KEYBOARD_8, + HID_KEYBOARD_9}; \ No newline at end of file diff --git a/applications/external/totp/workers/constants.h b/applications/external/totp/workers/constants.h new file mode 100644 index 000000000..c314b6c16 --- /dev/null +++ b/applications/external/totp/workers/constants.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const uint8_t hid_number_keys[10]; \ No newline at end of file diff --git a/applications/external/totp/workers/type_code/type_code.h b/applications/external/totp/workers/type_code/type_code.h deleted file mode 100644 index 27f2e02d4..000000000 --- a/applications/external/totp/workers/type_code/type_code.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include -#include - -typedef uint8_t TotpTypeCodeWorkerEvent; - -typedef struct { - char* string; - uint8_t string_length; - FuriThread* thread; - FuriMutex* string_sync; - FuriHalUsbInterface* usb_mode_prev; -} TotpTypeCodeWorkerContext; - -enum TotpTypeCodeWorkerEvents { - TotpTypeCodeWorkerEventReserved = (1 << 0), - TotpTypeCodeWorkerEventStop = (1 << 1), - TotpTypeCodeWorkerEventType = (1 << 2) -}; - -TotpTypeCodeWorkerContext* totp_type_code_worker_start(); -void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context); -void totp_type_code_worker_notify( - TotpTypeCodeWorkerContext* context, - TotpTypeCodeWorkerEvent event); \ No newline at end of file diff --git a/applications/external/totp/workers/type_code/type_code.c b/applications/external/totp/workers/usb_type_code/usb_type_code.c similarity index 68% rename from applications/external/totp/workers/type_code/type_code.c rename to applications/external/totp/workers/usb_type_code/usb_type_code.c index f2b4c9b9e..3132e2317 100644 --- a/applications/external/totp/workers/type_code/type_code.c +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.c @@ -1,19 +1,8 @@ -#include "type_code.h" +#include "usb_type_code.h" #include "../../services/convert/convert.h" +#include "../constants.h" -static const uint8_t hid_number_keys[10] = { - HID_KEYBOARD_0, - HID_KEYBOARD_1, - HID_KEYBOARD_2, - HID_KEYBOARD_3, - HID_KEYBOARD_4, - HID_KEYBOARD_5, - HID_KEYBOARD_6, - HID_KEYBOARD_7, - HID_KEYBOARD_8, - HID_KEYBOARD_9}; - -static void totp_type_code_worker_restore_usb_mode(TotpTypeCodeWorkerContext* context) { +static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) { if(context->usb_mode_prev != NULL) { furi_hal_usb_set_config(context->usb_mode_prev, NULL); context->usb_mode_prev = NULL; @@ -21,10 +10,10 @@ static void totp_type_code_worker_restore_usb_mode(TotpTypeCodeWorkerContext* co } static inline bool totp_type_code_worker_stop_requested() { - return furi_thread_flags_get() & TotpTypeCodeWorkerEventStop; + return furi_thread_flags_get() & TotpUsbTypeCodeWorkerEventStop; } -static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) { +static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* context) { context->usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); @@ -57,6 +46,7 @@ static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) } static int32_t totp_type_code_worker_callback(void* context) { + furi_assert(context); FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); if(context_mutex == NULL) { return 251; @@ -64,14 +54,14 @@ static int32_t totp_type_code_worker_callback(void* context) { while(true) { uint32_t flags = furi_thread_flags_wait( - TotpTypeCodeWorkerEventStop | TotpTypeCodeWorkerEventType, + TotpUsbTypeCodeWorkerEventStop | TotpUsbTypeCodeWorkerEventType, FuriFlagWaitAny, FuriWaitForever); furi_check((flags & FuriFlagError) == 0); //-V562 - if(flags & TotpTypeCodeWorkerEventStop) break; + if(flags & TotpUsbTypeCodeWorkerEventStop) break; if(furi_mutex_acquire(context_mutex, FuriWaitForever) == FuriStatusOk) { - if(flags & TotpTypeCodeWorkerEventType) { + if(flags & TotpUsbTypeCodeWorkerEventType) { totp_type_code_worker_type_code(context); } @@ -84,13 +74,18 @@ static int32_t totp_type_code_worker_callback(void* context) { return 0; } -TotpTypeCodeWorkerContext* totp_type_code_worker_start() { - TotpTypeCodeWorkerContext* context = malloc(sizeof(TotpTypeCodeWorkerContext)); +TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync) { + TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext)); furi_check(context != NULL); - context->string_sync = furi_mutex_alloc(FuriMutexTypeNormal); + context->string = code_buf; + context->string_length = code_buf_length; + context->string_sync = code_buf_update_sync; context->thread = furi_thread_alloc(); context->usb_mode_prev = NULL; - furi_thread_set_name(context->thread, "TOTPHidWorker"); + furi_thread_set_name(context->thread, "TOTPUsbHidWorker"); furi_thread_set_stack_size(context->thread, 1024); furi_thread_set_context(context->thread, context); furi_thread_set_callback(context->thread, totp_type_code_worker_callback); @@ -98,19 +93,18 @@ TotpTypeCodeWorkerContext* totp_type_code_worker_start() { return context; } -void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context) { +void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context) { furi_assert(context != NULL); - furi_thread_flags_set(furi_thread_get_id(context->thread), TotpTypeCodeWorkerEventStop); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpUsbTypeCodeWorkerEventStop); furi_thread_join(context->thread); furi_thread_free(context->thread); - furi_mutex_free(context->string_sync); totp_type_code_worker_restore_usb_mode(context); free(context); } -void totp_type_code_worker_notify( - TotpTypeCodeWorkerContext* context, - TotpTypeCodeWorkerEvent event) { +void totp_usb_type_code_worker_notify( + TotpUsbTypeCodeWorkerContext* context, + TotpUsbTypeCodeWorkerEvent event) { furi_assert(context != NULL); furi_thread_flags_set(furi_thread_get_id(context->thread), event); } \ No newline at end of file diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.h b/applications/external/totp/workers/usb_type_code/usb_type_code.h new file mode 100644 index 000000000..94fddcc59 --- /dev/null +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +typedef uint8_t TotpUsbTypeCodeWorkerEvent; + +typedef struct { + char* string; + uint8_t string_length; + FuriThread* thread; + FuriMutex* string_sync; + FuriHalUsbInterface* usb_mode_prev; +} TotpUsbTypeCodeWorkerContext; + +enum TotpUsbTypeCodeWorkerEvents { + TotpUsbTypeCodeWorkerEventReserved = (1 << 0), + TotpUsbTypeCodeWorkerEventStop = (1 << 1), + TotpUsbTypeCodeWorkerEventType = (1 << 2) +}; + +TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync); +void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context); +void totp_usb_type_code_worker_notify( + TotpUsbTypeCodeWorkerContext* context, + TotpUsbTypeCodeWorkerEvent event); \ No newline at end of file