MX 2 rokov pred
rodič
commit
7fc2efb776

+ 10 - 1
base_pack/totp/app_api_table_i.h

@@ -6,6 +6,7 @@
 #include "services/crypto/crypto_facade.h"
 #include "ui/scene_director.h"
 #include "services/config/config.h"
+#include "services/kb_layouts/kb_layout_provider.h"
 #include "cli/cli_helpers.h"
 #include "workers/bt_type_code/bt_type_code.h"
 
@@ -65,4 +66,12 @@ static constexpr auto app_api_table = sort(create_array_t<sym_entry>(
     API_METHOD(totp_bt_type_code_worker_free, void, (TotpBtTypeCodeWorkerContext*)),
     API_METHOD(token_info_set_token_type_from_str, bool, (TokenInfo*, const FuriString*)),
     API_METHOD(token_info_set_token_counter_from_str, bool, (TokenInfo*, const FuriString*)),
-    API_METHOD(token_info_get_type_as_cstr, const char*, (const TokenInfo*))));
+    API_METHOD(token_info_get_type_as_cstr, const char*, (const TokenInfo*)),
+    API_METHOD(
+        totp_kb_layout_provider_get_layout_by_name,
+        bool,
+        (const char*, AutomationKeyboardLayout*)),
+    API_METHOD(
+        totp_kb_layout_provider_get_layout_name,
+        bool,
+        (AutomationKeyboardLayout, char*, size_t))));

+ 1 - 4
base_pack/totp/application.fam

@@ -7,7 +7,7 @@ App(
     requires=["gui", "cli", "dialogs", "storage", "input", "notification", "bt"],
     stack_size=2 * 1024,
     order=20,
-    fap_version="5.80",
+    fap_version="5.91",
     fap_author="Alexander Kopachov (@akopachov)",
     fap_description="Software-based TOTP/HOTP authenticator for Flipper Zero device",
     fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",
@@ -19,9 +19,6 @@ App(
         Lib(
             name="base32",
         ),
-        Lib(
-            name="timezone_utils",
-        ),
         Lib(
             name="polyfills",
         ),

+ 1 - 1
base_pack/totp/assets/cli/cli_help.txt

@@ -53,5 +53,5 @@ Options:
   -s             Update token secret
   -f             Force command to do not ask user for interactive confirmation
   -c <slot>      New crypto key slot. Must be between 12 and 100
-  -k <layout>    Automation keyboard layout. Must be one of: QWERTY, AZERTY, QWERTZ
+  -k <layout>    Automation keyboard layout. Must be one of: QWERTY, AZERTY, QWERTZ, Czech, Dvorak, Hungarian, Slovak
   -w <delay>     Automation initial delay in seconds. Must be positive float value [default: 0.5]

BIN
base_pack/totp/assets/kb_layouts.klx


+ 6 - 37
base_pack/totp/cli/plugins/automation/automation.c

@@ -4,6 +4,7 @@
 #include "../../cli_shared_methods.h"
 #include "../../cli_plugin_interface.h"
 #include "../../../services/config/config.h"
+#include "../../../services/kb_layouts/kb_layout_provider.h"
 #include "../../../ui/scene_director.h"
 #include "../../../config/app/config.h"
 
@@ -13,9 +14,6 @@
 #ifdef TOTP_BADBT_AUTOMATION_ENABLED
 #define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt"
 #endif
-#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY "QWERTY"
-#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY "AZERTY"
-#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTZ "QWERTZ"
 #define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX "-k"
 #define TOTP_CLI_COMMAND_AUTOMATION_ARG_INITIAL_DELAY_PREFIX "-w"
 
@@ -46,23 +44,9 @@ static void print_method(AutomationMethod method, const char* color) {
 }
 
 static void print_kb_layout(AutomationKeyboardLayout layout, const char* color) {
-    char* layoutToPrint;
-    switch(layout) {
-    case AutomationKeyboardLayoutQWERTY:
-        layoutToPrint = TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY;
-        break;
-    case AutomationKeyboardLayoutAZERTY:
-        layoutToPrint = TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY;
-        break;
-    case AutomationKeyboardLayoutQWERTZ:
-        layoutToPrint = TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTZ;
-        break;
-    default:
-        furi_crash("Unknown automation keyboard layout");
-        break;
-    }
-
-    TOTP_CLI_PRINTF_COLORFUL(color, "%s", layoutToPrint);
+    char layoutToPrint[TOTP_KB_LAYOUT_NAME_MAX_LENGTH + 1];
+    totp_kb_layout_provider_get_layout_name(layout, &layoutToPrint[0], sizeof(layoutToPrint));
+    TOTP_CLI_PRINTF_COLORFUL(color, "%s", &layoutToPrint[0]);
 }
 
 static void print_initial_delay(uint16_t initial_delay, const char* color) {
@@ -70,22 +54,6 @@ static void print_initial_delay(uint16_t initial_delay, const char* color) {
     TOTP_CLI_PRINTF_COLORFUL(color, "%.1f", delay_sec);
 }
 
-static bool
-    parse_automation_keyboard_layout(const FuriString* str, AutomationKeyboardLayout* out) {
-    bool result = true;
-    if(furi_string_cmpi_str(str, TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY) == 0) {
-        *out = AutomationKeyboardLayoutQWERTY;
-    } else if(furi_string_cmpi_str(str, TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY) == 0) {
-        *out = AutomationKeyboardLayoutAZERTY;
-    } else if(furi_string_cmpi_str(str, TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTZ) == 0) {
-        *out = AutomationKeyboardLayoutQWERTZ;
-    } else {
-        result = false;
-    }
-
-    return result;
-}
-
 static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
     if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
         return;
@@ -113,7 +81,8 @@ static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
 #endif
         else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX) == 0) {
             if(!args_read_string_and_trim(args, temp_str) ||
-               !parse_automation_keyboard_layout(temp_str, &new_kb_layout)) {
+               !totp_kb_layout_provider_get_layout_by_name(
+                   furi_string_get_cstr(temp_str), &new_kb_layout)) {
                 args_valid = false;
                 break;
             }

+ 0 - 16
base_pack/totp/lib/timezone_utils/timezone_utils.c

@@ -1,16 +0,0 @@
-#include "timezone_utils.h"
-
-int32_t timezone_offset_from_hours(float hours) {
-    return hours * 3600.0f;
-}
-
-uint64_t timezone_offset_apply(uint64_t time, int32_t offset) {
-    uint64_t for_time_adjusted;
-    if(offset > 0) {
-        for_time_adjusted = time - offset;
-    } else {
-        for_time_adjusted = time + (-offset);
-    }
-
-    return for_time_adjusted;
-}

+ 0 - 18
base_pack/totp/lib/timezone_utils/timezone_utils.h

@@ -1,18 +0,0 @@
-#pragma once
-
-#include <inttypes.h>
-
-/**
- * @brief Calculates timezone offset in seconds given timezone offset in hours.
- * @param hours timezone offset in hours
- * @return Timezone offset in seconds.
- */
-int32_t timezone_offset_from_hours(float hours);
-
-/**
- * @brief Applies timezone offset to a given time.
- * @param time time to apply offset to.
- * @param offset timezone offset in seconds.
- * @return Time with timezone offset applied.
- */
-uint64_t timezone_offset_apply(uint64_t time, int32_t offset);

+ 15 - 3
base_pack/totp/services/config/config.c

@@ -9,6 +9,7 @@
 #include "../../types/common.h"
 #include "../../types/token_info.h"
 #include "../../config/app/config.h"
+#include "../kb_layouts/kb_layout_provider.h"
 #include "../crypto/crypto_facade.h"
 #include "../crypto/constants.h"
 #include "migrations/common_migration.h"
@@ -173,7 +174,7 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
         flipper_format_write_uint32(
             fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1);
 
-        tmp_uint32 = AutomationKeyboardLayoutQWERTY;
+        tmp_uint32 = TOTP_DEFAULT_KB_LAYOUT;
         flipper_format_write_uint32(
             fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1);
 
@@ -507,7 +508,7 @@ bool totp_config_file_load(PluginState* const plugin_state) {
 
         if(!flipper_format_read_uint32(
                fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
-            tmp_uint32 = AutomationKeyboardLayoutQWERTY;
+            tmp_uint32 = TOTP_DEFAULT_KB_LAYOUT;
         }
 
         plugin_state->automation_kb_layout = tmp_uint32;
@@ -737,7 +738,18 @@ bool totp_config_file_ensure_latest_encryption(
     uint8_t pin_length) {
     bool result = true;
     if(plugin_state->crypto_settings.crypto_version < CRYPTO_LATEST_VERSION) {
-        FURI_LOG_I(LOGGING_TAG, "Migration to crypto v%d is needed", CRYPTO_LATEST_VERSION);
+        FURI_LOG_I(LOGGING_TAG, "Migration crypto from v%" PRIu8 " to v%" PRIu8 " is needed", plugin_state->crypto_settings.crypto_version, CRYPTO_LATEST_VERSION);
+        
+#ifndef TOTP_OBSOLETE_CRYPTO_V1_COMPATIBILITY_ENABLED
+        if (plugin_state->crypto_settings.crypto_version == 1) {
+            furi_crash("Authenticator: Crypto v1 is not supported");
+        }
+#endif
+#ifndef TOTP_OBSOLETE_CRYPTO_V2_COMPATIBILITY_ENABLED
+        if (plugin_state->crypto_settings.crypto_version == 2) {
+            furi_crash("Authenticator: Crypto v2 is not supported");
+        }
+#endif
         char* backup_path = totp_config_file_backup(plugin_state);
         if(backup_path != NULL) {
             free(backup_path);

+ 1 - 1
base_pack/totp/services/config/constants.h

@@ -4,7 +4,7 @@
 
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/totp")
 #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
-#define CONFIG_FILE_ACTUAL_VERSION (11)
+#define CONFIG_FILE_ACTUAL_VERSION (12)
 
 #define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
 #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"

+ 8 - 12
base_pack/totp/services/config/migrations/common_migration.c

@@ -1,7 +1,7 @@
 #include "common_migration.h"
 #include "../constants.h"
 #include "../../../types/token_info.h"
-#include "../../../types/automation_kb_layout.h"
+#include "../../kb_layouts/kb_layout_provider.h"
 #include <flipper_format/flipper_format_i.h>
 
 #define TOTP_OLD_CONFIG_KEY_BASE_IV "BaseIV"
@@ -98,19 +98,15 @@ bool totp_config_migrate_to_latest(
 
         flipper_format_rewind(fff_backup_data_file);
 
-        if(flipper_format_read_string(
-               fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str)) {
-            flipper_format_write_string(
-                fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str);
-        } else {
-            uint32_t default_automation_kb_layout = AutomationKeyboardLayoutQWERTY;
-            flipper_format_write_uint32(
-                fff_data_file,
-                TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT,
-                &default_automation_kb_layout,
-                1);
+        uint32_t kb_layout;
+        if(!flipper_format_read_uint32(
+               fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &kb_layout, 1)) {
+            kb_layout = TOTP_DEFAULT_KB_LAYOUT;
         }
 
+        flipper_format_write_uint32(
+            fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &kb_layout, 1);
+
         flipper_format_rewind(fff_backup_data_file);
 
         if(flipper_format_read_string(

+ 160 - 0
base_pack/totp/services/kb_layouts/kb_layout_provider.c

@@ -0,0 +1,160 @@
+#include "kb_layout_provider.h"
+
+#include <storage/storage.h>
+#include <toolbox/stream/stream.h>
+#include <toolbox/stream/file_stream.h>
+
+#define KB_LAYOUTS_FILE EXT_PATH("apps_assets/totp/kb_layouts.klx")
+
+bool totp_kb_layout_provider_get_layout_data(AutomationKeyboardLayout kb_layout, uint16_t* buffer) {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Stream* stream = file_stream_alloc(storage);
+
+    bool result = false;
+    do {
+        if(!file_stream_open(stream, KB_LAYOUTS_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            break;
+        }
+
+        if(!stream_seek(
+               stream,
+               sizeof(uint8_t) + kb_layout * (TOTP_KB_LAYOUT_NAME_MAX_LENGTH + sizeof(uint16_t)) +
+                   TOTP_KB_LAYOUT_NAME_MAX_LENGTH,
+               StreamOffsetFromStart)) {
+            break;
+        }
+
+        uint16_t offset;
+        if(stream_read(stream, (uint8_t*)&offset, sizeof(uint16_t)) != sizeof(uint16_t)) {
+            break;
+        }
+
+        if(!stream_seek(stream, offset, StreamOffsetFromStart)) {
+            break;
+        }
+
+        size_t bytes_to_read = TOTP_KB_LAYOUT_DATA_LENGTH * sizeof(uint16_t);
+        if(stream_read(stream, (uint8_t*)buffer, bytes_to_read) != bytes_to_read) {
+            break;
+        }
+
+        result = true;
+    } while(false);
+
+    file_stream_close(stream);
+    stream_free(stream);
+    furi_record_close(RECORD_STORAGE);
+
+    return result;
+}
+
+uint8_t totp_kb_layout_provider_get_layouts_count() {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Stream* stream = file_stream_alloc(storage);
+
+    uint8_t result = 0;
+    do {
+        if(!file_stream_open(stream, KB_LAYOUTS_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            break;
+        }
+
+        if(!stream_rewind(stream)) {
+            break;
+        }
+
+        if(stream_read(stream, &result, 1) != 1) {
+            break;
+        }
+    } while(false);
+
+    file_stream_close(stream);
+    stream_free(stream);
+    furi_record_close(RECORD_STORAGE);
+
+    return result;
+}
+
+bool totp_kb_layout_provider_get_layout_name(
+    AutomationKeyboardLayout kb_layout,
+    char* buffer,
+    size_t buffer_length) {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Stream* stream = file_stream_alloc(storage);
+
+    bool result = false;
+    do {
+        if(!file_stream_open(stream, KB_LAYOUTS_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            break;
+        }
+
+        if(!stream_seek(
+               stream,
+               sizeof(uint8_t) + kb_layout * (TOTP_KB_LAYOUT_NAME_MAX_LENGTH + sizeof(uint16_t)),
+               StreamOffsetFromStart)) {
+            break;
+        }
+
+        size_t bytes_to_read = M_MIN(TOTP_KB_LAYOUT_NAME_MAX_LENGTH, buffer_length);
+        if(stream_read(stream, (uint8_t*)buffer, bytes_to_read) != bytes_to_read) {
+            break;
+        }
+
+        buffer[buffer_length - 1] = '\0';
+
+        result = true;
+    } while(false);
+
+    file_stream_close(stream);
+    stream_free(stream);
+    furi_record_close(RECORD_STORAGE);
+
+    return result;
+}
+
+bool totp_kb_layout_provider_get_layout_by_name(
+    const char* name,
+    AutomationKeyboardLayout* kb_layout) {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Stream* stream = file_stream_alloc(storage);
+
+    uint8_t count = 0;
+    bool found = false;
+    do {
+        if(!file_stream_open(stream, KB_LAYOUTS_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            break;
+        }
+
+        if(!stream_rewind(stream)) {
+            break;
+        }
+
+        if(stream_read(stream, &count, 1) != 1) {
+            break;
+        }
+
+        char current_name[TOTP_KB_LAYOUT_NAME_MAX_LENGTH + 1];
+        for(AutomationKeyboardLayout i = 0; i < count; i++) {
+            if(stream_read(stream, (uint8_t*)&current_name[0], TOTP_KB_LAYOUT_NAME_MAX_LENGTH) !=
+               TOTP_KB_LAYOUT_NAME_MAX_LENGTH) {
+                break;
+            }
+
+            current_name[TOTP_KB_LAYOUT_NAME_MAX_LENGTH] = '\0';
+            if(strncasecmp(name, &current_name[0], TOTP_KB_LAYOUT_NAME_MAX_LENGTH) == 0) {
+                found = true;
+                *kb_layout = i;
+                break;
+            }
+
+            if(!stream_seek(stream, sizeof(uint16_t), StreamOffsetFromCurrent)) {
+                break;
+            }
+        }
+    } while(false);
+
+    file_stream_close(stream);
+    stream_free(stream);
+    furi_record_close(RECORD_STORAGE);
+
+    return found;
+}

+ 53 - 0
base_pack/totp/services/kb_layouts/kb_layout_provider.h

@@ -0,0 +1,53 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "../../types/automation_kb_layout.h"
+
+#define TOTP_DEFAULT_KB_LAYOUT (0)
+#define TOTP_KB_LAYOUT_DATA_LENGTH (36)
+#define TOTP_KB_LAYOUT_NAME_MAX_LENGTH (10)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Loads keyboard layout into \c buffer
+ * @param kb_layout keyboard layout
+ * @param[out] buffer buffer to load keyboard layout into
+ * @return \c true if keyboard layout loaded successfully; \c false otherwise
+ */
+bool totp_kb_layout_provider_get_layout_data(AutomationKeyboardLayout kb_layout, uint16_t* buffer);
+
+/**
+ * @brief Gets total keyboard layouts count
+ * @return total keyboard layouts count
+ */
+uint8_t totp_kb_layout_provider_get_layouts_count();
+
+/**
+ * @brief Gets keyboard layout name of a given \c kb_layout into \c buffer
+ * @param kb_layout keyboard layout
+ * @param[out] buffer buffer to get keyboard layout name into
+ * @param buffer_length available buffer length
+ * @return \c true if keyboard layout name found successfully; \c false otherwise
+ */
+bool totp_kb_layout_provider_get_layout_name(
+    AutomationKeyboardLayout kb_layout,
+    char* buffer,
+    size_t buffer_length);
+
+/**
+ * @brief Gets keyboard layout by \c name
+ * @param name keyboard layout name
+ * @param[out] kb_layout keyboard layout
+ * @return \c true if keyboard layout found successfully; \c false otherwise
+ */
+bool totp_kb_layout_provider_get_layout_by_name(
+    const char* name,
+    AutomationKeyboardLayout* kb_layout);
+
+#ifdef __cplusplus
+}
+#endif

+ 15 - 1
base_pack/totp/services/totp/totp.c

@@ -3,7 +3,6 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <math.h>
-#include <timezone_utils.h>
 #include "../../config/wolfssl/config.h"
 #include <wolfssl/wolfcrypt/hmac.h>
 #ifdef NO_INLINE
@@ -15,6 +14,21 @@
 
 #define HMAC_MAX_RESULT_SIZE WC_SHA512_DIGEST_SIZE
 
+static int32_t timezone_offset_from_hours(float hours) {
+    return hours * 3600.0f;
+}
+
+static uint64_t timezone_offset_apply(uint64_t time, int32_t offset) {
+    uint64_t for_time_adjusted;
+    if(offset > 0) {
+        for_time_adjusted = time - offset;
+    } else {
+        for_time_adjusted = time + (-offset);
+    }
+
+    return for_time_adjusted;
+}
+
 /**
  * @brief Generates the timeblock for a time in seconds.
  *        Timeblocks are the amount of intervals in a given time. For example,

+ 2 - 6
base_pack/totp/types/automation_kb_layout.h

@@ -1,9 +1,5 @@
 #pragma once
 
-typedef uint8_t AutomationKeyboardLayout;
+#include <stdint.h>
 
-enum AutomationKeyboardLayouts {
-    AutomationKeyboardLayoutQWERTY = 0,
-    AutomationKeyboardLayoutAZERTY = 1,
-    AutomationKeyboardLayoutQWERTZ = 2
-};
+typedef uint8_t AutomationKeyboardLayout;

+ 18 - 5
base_pack/totp/ui/scenes/app_settings/totp_app_settings.c

@@ -9,6 +9,7 @@
 #include "../../constants.h"
 #include "../../../services/config/config.h"
 #include "../../../services/convert/convert.h"
+#include "../../../services/kb_layouts/kb_layout_provider.h"
 #include <roll_value.h>
 #include "../../../config/app/config.h"
 #ifdef TOTP_BADBT_AUTOMATION_ENABLED
@@ -27,7 +28,6 @@ static const char* AUTOMATION_LIST[] = {
     "BT and USB"
 #endif
 };
-static const char* BAD_KB_LAYOUT_LIST[] = {"QWERTY", "AZERTY", "QWERTZ"};
 static const char* FONT_TEST_STR = "0123BCD";
 
 typedef enum {
@@ -50,6 +50,8 @@ typedef struct {
     AutomationMethod automation_method;
     uint16_t y_offset;
     AutomationKeyboardLayout automation_kb_layout;
+    uint8_t automation_kb_layout_count;
+    char automation_kb_layout_name[TOTP_KB_LAYOUT_NAME_MAX_LENGTH + 1];
     Control selected_control;
     uint8_t active_font_index;
     FontInfo* active_font;
@@ -80,6 +82,13 @@ static void update_formatted_automation_initial_delay(SceneState* scene_state) {
         (double)(scene_state->automation_initial_delay / 1000.0f));
 }
 
+static void update_formatted_automation_kb_layout_name(SceneState* scene_state) {
+    totp_kb_layout_provider_get_layout_name(
+        scene_state->automation_kb_layout,
+        &scene_state->automation_kb_layout_name[0],
+        sizeof(scene_state->automation_kb_layout_name));
+}
+
 void totp_scene_app_settings_activate(PluginState* plugin_state) {
     SceneState* scene_state = malloc(sizeof(SceneState));
     furi_check(scene_state != NULL);
@@ -93,8 +102,9 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
     scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro;
     scene_state->automation_method =
         MIN(plugin_state->automation_method, COUNT_OF(AUTOMATION_LIST) - 1);
+    scene_state->automation_kb_layout_count = totp_kb_layout_provider_get_layouts_count();
     scene_state->automation_kb_layout =
-        MIN(plugin_state->automation_kb_layout, COUNT_OF(BAD_KB_LAYOUT_LIST) - 1);
+        MIN(plugin_state->automation_kb_layout, scene_state->automation_kb_layout_count - 1);
 
     scene_state->automation_initial_delay = plugin_state->automation_initial_delay;
     scene_state->total_fonts_count = totp_font_provider_get_fonts_count();
@@ -106,6 +116,7 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
     }
 
     update_formatted_automation_initial_delay(scene_state);
+    update_formatted_automation_kb_layout_name(scene_state);
 }
 
 void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) {
@@ -221,7 +232,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
             36,
             220 - scene_state->y_offset - group_offset,
             SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
-            BAD_KB_LAYOUT_LIST[scene_state->automation_kb_layout],
+            scene_state->automation_kb_layout_name,
             scene_state->selected_control == BadKeyboardLayoutSelect);
 
         canvas_draw_str_aligned(
@@ -325,8 +336,9 @@ bool totp_scene_app_settings_handle_event(
                     &scene_state->automation_kb_layout,
                     1,
                     0,
-                    COUNT_OF(BAD_KB_LAYOUT_LIST) - 1,
+                    scene_state->automation_kb_layout_count - 1,
                     RollOverflowBehaviorRoll);
+                update_formatted_automation_kb_layout_name(scene_state);
             } else if(scene_state->selected_control == AutomationDelaySelect) {
                 totp_roll_value_uint16_t(
                     &scene_state->automation_initial_delay,
@@ -369,8 +381,9 @@ bool totp_scene_app_settings_handle_event(
                     &scene_state->automation_kb_layout,
                     -1,
                     0,
-                    COUNT_OF(BAD_KB_LAYOUT_LIST) - 1,
+                    scene_state->automation_kb_layout_count - 1,
                     RollOverflowBehaviorRoll);
+                update_formatted_automation_kb_layout_name(scene_state);
             } else if(scene_state->selected_control == AutomationDelaySelect) {
                 totp_roll_value_uint16_t(
                     &scene_state->automation_initial_delay,

+ 2 - 2
base_pack/totp/version.h

@@ -1,5 +1,5 @@
 #pragma once
 
 #define TOTP_APP_VERSION_MAJOR (5)
-#define TOTP_APP_VERSION_MINOR (8)
-#define TOTP_APP_VERSION_PATCH (0)
+#define TOTP_APP_VERSION_MINOR (9)
+#define TOTP_APP_VERSION_PATCH (1)

+ 7 - 55
base_pack/totp/workers/type_code_common.c

@@ -1,39 +1,9 @@
 #include "type_code_common.h"
 #include <furi_hal_usb_hid.h>
 #include <furi/core/kernel.h>
+#include <furi/core/log.h>
 #include "../../services/convert/convert.h"
-
-#define HID_KEYS_MAP_LENGTH (36)
-
-static const uint8_t hid_qwerty_keys_map[HID_KEYS_MAP_LENGTH] = {
-    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,
-    HID_KEYBOARD_A, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E,
-    HID_KEYBOARD_F, HID_KEYBOARD_G, HID_KEYBOARD_H, HID_KEYBOARD_I, HID_KEYBOARD_J,
-    HID_KEYBOARD_K, HID_KEYBOARD_L, HID_KEYBOARD_M, HID_KEYBOARD_N, HID_KEYBOARD_O,
-    HID_KEYBOARD_P, HID_KEYBOARD_Q, HID_KEYBOARD_R, HID_KEYBOARD_S, HID_KEYBOARD_T,
-    HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Y,
-    HID_KEYBOARD_Z};
-
-static const uint8_t hid_azerty_keys_map[HID_KEYS_MAP_LENGTH] = {
-    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,
-    HID_KEYBOARD_Q, HID_KEYBOARD_B, HID_KEYBOARD_C,         HID_KEYBOARD_D, HID_KEYBOARD_E,
-    HID_KEYBOARD_F, HID_KEYBOARD_G, HID_KEYBOARD_H,         HID_KEYBOARD_I, HID_KEYBOARD_J,
-    HID_KEYBOARD_K, HID_KEYBOARD_L, HID_KEYBOARD_SEMICOLON, HID_KEYBOARD_N, HID_KEYBOARD_O,
-    HID_KEYBOARD_P, HID_KEYBOARD_A, HID_KEYBOARD_R,         HID_KEYBOARD_S, HID_KEYBOARD_T,
-    HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_Z,         HID_KEYBOARD_X, HID_KEYBOARD_Y,
-    HID_KEYBOARD_W};
-
-static const uint8_t hid_qwertz_keys_map[HID_KEYS_MAP_LENGTH] = {
-    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,
-    HID_KEYBOARD_A, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E,
-    HID_KEYBOARD_F, HID_KEYBOARD_G, HID_KEYBOARD_H, HID_KEYBOARD_I, HID_KEYBOARD_J,
-    HID_KEYBOARD_K, HID_KEYBOARD_L, HID_KEYBOARD_M, HID_KEYBOARD_N, HID_KEYBOARD_O,
-    HID_KEYBOARD_P, HID_KEYBOARD_Q, HID_KEYBOARD_R, HID_KEYBOARD_S, HID_KEYBOARD_T,
-    HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Z,
-    HID_KEYBOARD_Y};
+#include "../../services/kb_layouts/kb_layout_provider.h"
 
 static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
     if(features & TokenAutomationFeatureTypeSlower) {
@@ -69,24 +39,13 @@ void totp_type_code_worker_execute_automation(
     TokenAutomationFeature features,
     AutomationKeyboardLayout keyboard_layout,
     uint16_t initial_delay) {
-    furi_delay_ms(initial_delay);
-
-    const uint8_t* keyboard_layout_dict;
-    switch(keyboard_layout) {
-    case AutomationKeyboardLayoutQWERTY:
-        keyboard_layout_dict = &hid_qwerty_keys_map[0];
-        break;
-    case AutomationKeyboardLayoutAZERTY:
-        keyboard_layout_dict = &hid_azerty_keys_map[0];
-        break;
-    case AutomationKeyboardLayoutQWERTZ:
-        keyboard_layout_dict = &hid_qwertz_keys_map[0];
-        break;
-
-    default:
+    uint16_t keyboard_layout_dict[TOTP_KB_LAYOUT_DATA_LENGTH];
+    if(!totp_kb_layout_provider_get_layout_data(keyboard_layout, &keyboard_layout_dict[0])) {
         return;
     }
 
+    furi_delay_ms(initial_delay);
+
     uint32_t keystroke_delay = get_keystroke_delay(features);
 
     char cb_char;
@@ -97,16 +56,9 @@ void totp_type_code_worker_execute_automation(
             char_index = cb_char - 'A' + 10;
         }
 
-        if(char_index >= HID_KEYS_MAP_LENGTH) break;
+        if(char_index >= TOTP_KB_LAYOUT_DATA_LENGTH) break;
 
         uint16_t hid_kb_key = keyboard_layout_dict[char_index];
-
-        // For non-AZERTY press shift for all non-digit chars
-        // For AZERTY press shift for all characters
-        if(char_index > 9 || keyboard_layout == AutomationKeyboardLayoutAZERTY) {
-            hid_kb_key |= KEY_MOD_LEFT_SHIFT;
-        }
-
         totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features);
         furi_delay_ms(keystroke_delay);
         i++;