Преглед изворни кода

Implemented "type code in badusb mode"

* Implemented #21
Alexander Kopachov пре 3 година
родитељ
комит
329cf665de

+ 7 - 0
FAQ.md

@@ -27,8 +27,15 @@ Detailed description of file format can be found [here](docs/conf-file_descripti
 ## Is there a CLI?
 ## Is there a CLI?
 
 
 **YES!**
 **YES!**
+
 When Flipper Authenticator is running `totp` CLI is available for you to list, add or remove tokens. Run `totp help` to get list of available commands and arguments.
 When Flipper Authenticator is running `totp` CLI is available for you to list, add or remove tokens. Run `totp help` to get list of available commands and arguments.
 
 
+## Manually typing codes is boring, is there Bad USB mode?
+
+**YES!**
+
+Just pick the token you would like to auto-type then hold "arrow down" button for 1-2sec. and Flipper Authenticator will type it instead of you :)
+
 ## How to change\recover PIN?
 ## How to change\recover PIN?
 
 
 For now there is no way to change or recover PIN once it is set without loosing all the token secrets. If you would like to completely reset app settings including PIN and all the tokens - just delete `/ext/apps/Misc/totp.conf` file. Flipper Authenticator will create new empty file and you will be able to setup everything from scratch.
 For now there is no way to change or recover PIN once it is set without loosing all the token secrets. If you would like to completely reset app settings including PIN and all the tokens - just delete `/ext/apps/Misc/totp.conf` file. Flipper Authenticator will create new empty file and you will be able to setup everything from scratch.

+ 37 - 5
totp/scenes/generate_token/totp_scene_generate_token.c

@@ -13,19 +13,21 @@
 #include "../../services/roll_value/roll_value.h"
 #include "../../services/roll_value/roll_value.h"
 #include "../scene_director.h"
 #include "../scene_director.h"
 #include "../token_menu/totp_scene_token_menu.h"
 #include "../token_menu/totp_scene_token_menu.h"
+#include "../../services/hid_worker/hid_worker.h"
 
 
 #define TOKEN_LIFETIME 30
 #define TOKEN_LIFETIME 30
 #define DIGIT_TO_CHAR(digit) ((digit) + '0')
 #define DIGIT_TO_CHAR(digit) ((digit) + '0')
 
 
 typedef struct {
 typedef struct {
     uint16_t current_token_index;
     uint16_t current_token_index;
-    char last_code[9];
+    char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
     char* last_code_name;
     char* last_code_name;
     bool need_token_update;
     bool need_token_update;
     uint32_t last_token_gen_time;
     uint32_t last_token_gen_time;
+    TotpHidWorkerTypeContext* hid_worker_context;
 } SceneState;
 } SceneState;
 
 
-static const NotificationSequence sequence_short_vibro_and_sound = {
+static const NotificationSequence notification_sequence_new_token = {
     &message_display_backlight_on,
     &message_display_backlight_on,
     &message_green_255,
     &message_green_255,
     &message_vibro_on,
     &message_vibro_on,
@@ -36,6 +38,19 @@ static const NotificationSequence sequence_short_vibro_and_sound = {
     NULL,
     NULL,
 };
 };
 
 
+static const NotificationSequence notification_sequence_badusb = {
+    &message_vibro_on,
+    &message_note_d5,
+    &message_delay_50,
+    &message_note_e4,
+    &message_delay_50,
+    &message_note_f3,
+    &message_delay_50,
+    &message_vibro_off,
+    &message_sound_off,
+    NULL,
+};
+
 static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
 static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
     uint8_t str_token_length = 0;
     uint8_t str_token_length = 0;
     if(len == TOTP_8_DIGITS) {
     if(len == TOTP_8_DIGITS) {
@@ -137,6 +152,9 @@ void totp_scene_generate_token_activate(
     plugin_state->current_scene_state = scene_state;
     plugin_state->current_scene_state = scene_state;
     FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
     FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
     update_totp_params(plugin_state);
     update_totp_params(plugin_state);
+    scene_state->hid_worker_context = totp_hid_worker_start();
+    scene_state->hid_worker_context->string = &scene_state->last_code[0];
+    scene_state->hid_worker_context->string_length = TOTP_TOKEN_DIGITS_MAX_COUNT + 1;
 }
 }
 
 
 void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
 void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
@@ -172,12 +190,13 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
         scene_state->need_token_update = false;
         scene_state->need_token_update = false;
         scene_state->last_token_gen_time = curr_ts;
         scene_state->last_token_gen_time = curr_ts;
 
 
-        TokenInfo* tokenInfo =
+        const TokenInfo* tokenInfo =
             (TokenInfo*)(list_element_at(
             (TokenInfo*)(list_element_at(
                              plugin_state->tokens_list, scene_state->current_token_index)
                              plugin_state->tokens_list, scene_state->current_token_index)
                              ->data);
                              ->data);
 
 
         if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
         if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
+            furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever);
             size_t key_length;
             size_t key_length;
             uint8_t* key = totp_crypto_decrypt(
             uint8_t* key = totp_crypto_decrypt(
                 tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
                 tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
@@ -196,11 +215,14 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
             memset_s(key, key_length, 0, key_length);
             memset_s(key, key_length, 0, key_length);
             free(key);
             free(key);
         } else {
         } else {
+            furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever);
             i_token_to_str(0, scene_state->last_code, tokenInfo->digits);
             i_token_to_str(0, scene_state->last_code, tokenInfo->digits);
         }
         }
 
 
+        furi_mutex_release(scene_state->hid_worker_context->string_sync);
+
         if(is_new_token_time) {
         if(is_new_token_time) {
-            notification_message(plugin_state->notification, &sequence_short_vibro_and_sound);
+            notification_message(plugin_state->notification, &notification_sequence_new_token);
         }
         }
     }
     }
 
 
@@ -263,11 +285,19 @@ bool totp_scene_generate_token_handle_event(
         return false;
         return false;
     }
     }
 
 
+    SceneState* scene_state;
+    if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) {
+        scene_state = (SceneState*)plugin_state->current_scene_state;
+        totp_hid_worker_notify(scene_state->hid_worker_context, TotpHidWorkerEvtType);
+        notification_message(plugin_state->notification, &notification_sequence_badusb);
+        return true;
+    }
+
     if(event->input.type != InputTypePress) {
     if(event->input.type != InputTypePress) {
         return true;
         return true;
     }
     }
 
 
-    SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
+    scene_state = (SceneState*)plugin_state->current_scene_state;
     switch(event->input.key) {
     switch(event->input.key) {
     case InputKeyUp:
     case InputKeyUp:
         break;
         break;
@@ -312,6 +342,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
     if(plugin_state->current_scene_state == NULL) return;
     if(plugin_state->current_scene_state == NULL) return;
     SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
     SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
 
 
+    totp_hid_worker_stop(scene_state->hid_worker_context);
+
     free(scene_state);
     free(scene_state);
     plugin_state->current_scene_state = NULL;
     plugin_state->current_scene_state = NULL;
 }
 }

+ 100 - 0
totp/services/hid_worker/hid_worker.c

@@ -0,0 +1,100 @@
+#include "hid_worker.h"
+
+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_hid_worker_type_code(TotpHidWorkerTypeContext* context) {
+    FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
+    furi_hal_usb_unlock();
+    furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true);
+    uint8_t i = 0;
+    do {
+        furi_delay_ms(500);
+        i++;
+    } while(!furi_hal_hid_is_connected() && i < 100);
+
+    if(furi_hal_hid_is_connected() &&
+       furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
+        i = 0;
+        while(i < context->string_length && context->string[i] != 0) {
+            uint8_t digit = context->string[i] - '0';
+            if(digit > 9) break;
+            uint8_t hid_kb_key = hid_number_keys[digit];
+            furi_hal_hid_kb_press(hid_kb_key);
+            furi_delay_ms(30);
+            furi_hal_hid_kb_release(hid_kb_key);
+            i++;
+        }
+
+        furi_mutex_release(context->string_sync);
+
+        furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
+        furi_delay_ms(30);
+        furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
+
+        furi_delay_ms(100);
+    }
+
+    furi_hal_usb_set_config(usb_mode_prev, NULL);
+}
+
+static int32_t totp_hid_worker_callback(void* context) {
+    ValueMutex context_mutex;
+    if(!init_mutex(&context_mutex, context, sizeof(TotpHidWorkerTypeContext))) {
+        return 251;
+    }
+
+    while(true) {
+        uint32_t flags = furi_thread_flags_wait(
+            TotpHidWorkerEvtStop | TotpHidWorkerEvtType, FuriFlagWaitAny, FuriWaitForever);
+        furi_check((flags & FuriFlagError) == 0); //-V562
+        if(flags & TotpHidWorkerEvtStop) break;
+
+        TotpHidWorkerTypeContext* h_context = acquire_mutex_block(&context_mutex);
+        if(flags & TotpHidWorkerEvtType) {
+            totp_hid_worker_type_code(h_context);
+        }
+
+        release_mutex(&context_mutex, h_context);
+    }
+
+    delete_mutex(&context_mutex);
+
+    return 0;
+}
+
+TotpHidWorkerTypeContext* totp_hid_worker_start() {
+    TotpHidWorkerTypeContext* context = malloc(sizeof(TotpHidWorkerTypeContext));
+    furi_check(context != NULL);
+    context->string_sync = furi_mutex_alloc(FuriMutexTypeNormal);
+    context->thread = furi_thread_alloc();
+    furi_thread_set_name(context->thread, "TOTPHidWorker");
+    furi_thread_set_stack_size(context->thread, 1024);
+    furi_thread_set_context(context->thread, context);
+    furi_thread_set_callback(context->thread, totp_hid_worker_callback);
+    furi_thread_start(context->thread);
+    return context;
+}
+
+void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) {
+    furi_assert(context);
+    furi_thread_flags_set(furi_thread_get_id(context->thread), TotpHidWorkerEvtStop);
+    furi_thread_join(context->thread);
+    furi_thread_free(context->thread);
+    furi_mutex_free(context->string_sync);
+    free(context);
+}
+
+void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event) {
+    furi_assert(context);
+    furi_thread_flags_set(furi_thread_get_id(context->thread), event);
+}

+ 22 - 0
totp/services/hid_worker/hid_worker.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdlib.h>
+#include <furi/furi.h>
+#include <furi_hal.h>
+
+typedef struct {
+    char* string;
+    uint8_t string_length;
+    FuriThread* thread;
+    FuriMutex* string_sync;
+} TotpHidWorkerTypeContext;
+
+typedef enum {
+    TotpHidWorkerEvtReserved = (1 << 0),
+    TotpHidWorkerEvtStop = (1 << 1),
+    TotpHidWorkerEvtType = (1 << 2)
+} TotpHidWorkerEvtFlags;
+
+TotpHidWorkerTypeContext* totp_hid_worker_start();
+void totp_hid_worker_stop(TotpHidWorkerTypeContext* context);
+void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event);

+ 2 - 0
totp/types/token_info.h

@@ -6,6 +6,8 @@ typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo;
 
 
 typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount;
 typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount;
 
 
+#define TOTP_TOKEN_DIGITS_MAX_COUNT 8
+
 typedef struct {
 typedef struct {
     uint8_t* token;
     uint8_t* token;
     size_t token_length;
     size_t token_length;