Kaynağa Gözat

Refactoring (#130)

Alexander Kopachov 2 yıl önce
ebeveyn
işleme
861399b029

+ 12 - 55
build.ps1

@@ -12,21 +12,18 @@ $build_commands = @(
         FbtSwitch = "od";
         FbtSwitch = "od";
         FirmwarePath = "flipperzero-firmware_official_dev";
         FirmwarePath = "flipperzero-firmware_official_dev";
         ArtifactName = "totp_official-dev_unleashed_fw{FEATURES_SUFFIX}.fap";
         ArtifactName = "totp_official-dev_unleashed_fw{FEATURES_SUFFIX}.fap";
-        FW_CDEF = "TOTP_FIRMWARE_OFFICIAL_DEV"
     }
     }
     [PSCustomObject]@{
     [PSCustomObject]@{
         Name = "Official Stable";
         Name = "Official Stable";
         FbtSwitch = "os";
         FbtSwitch = "os";
         FirmwarePath = "flipperzero-firmware_official_stable";
         FirmwarePath = "flipperzero-firmware_official_stable";
         ArtifactName = "totp_official-stable_fw{FEATURES_SUFFIX}.fap";
         ArtifactName = "totp_official-stable_fw{FEATURES_SUFFIX}.fap";
-        FW_CDEF = "TOTP_FIRMWARE_OFFICIAL_STABLE"
     }
     }
     [PSCustomObject]@{
     [PSCustomObject]@{
         Name = "Xtreme";
         Name = "Xtreme";
         FbtSwitch = "x";
         FbtSwitch = "x";
         FirmwarePath = "flipperzero-firmware_xtreme";
         FirmwarePath = "flipperzero-firmware_xtreme";
         ArtifactName = "totp_xtreme_fw{FEATURES_SUFFIX}.fap";
         ArtifactName = "totp_xtreme_fw{FEATURES_SUFFIX}.fap";
-        FW_CDEF = "TOTP_FIRMWARE_XTREME"
     }
     }
 )
 )
 
 
@@ -38,51 +35,10 @@ if (!(Test-Path -PathType Container "build")) {
     Remove-Item "build\*" -Recurse -Force
     Remove-Item "build\*" -Recurse -Force
 }
 }
 
 
-function Features-Configure {
-    param (
-        [string[]]$enable,
-        [string[]]$disable,
-        [string]$set
-    )
-
-    $featuresConfigContent = Get-Content "totp/features_config.h" -Raw
-    $appManifestContent = Get-Content "totp/application.fam" -Raw
-
-    foreach ($feature in $enable) {
-        $featuresConfigContent = $featuresConfigContent -replace "(#undef)(\s+$feature(\s|$)+)", '#define$2'
-        [regex]$appManifestFeaturePattern="(#ifdef $feature\r?\n)((.+\r?\n)+)(#\s*endif)"
-        $appManifestContent = $appManifestFeaturePattern.Replace($appManifestContent, { param($match)
-            return $match.Groups[1].Value + 
-            ($match.Groups[2].Value -replace '^(\s*)#(.+)$', '$1$2') + 
-            $match.Groups[4].Value
-        })
-    }
-
-    foreach ($feature in $disable) {
-        $featuresConfigContent = $featuresConfigContent -replace "(#define)(\s+$feature(\s|$)+)", '#undef$2'
-        [regex]$appManifestFeaturePattern="(#ifdef $feature\r?\n)((.+\r?\n)+)(#\s*endif)"
-        $appManifestContent = $appManifestFeaturePattern.Replace($appManifestContent, { param($match)
-            return $match.Groups[1].Value + 
-            ($match.Groups[2].Value -replace '^(\s*)(.+)$', '#$1$2') + 
-            $match.Groups[4].Value
-        })
-    }
-
-    if ($set) {
-        $keyValue = $set -split '='
-        $key = $keyValue[0]
-        $value = $keyValue[1]
-
-        $featuresConfigContent = $featuresConfigContent -replace "(#define +)($key)( +.+)(($|\r?\n?)+)", "`$1`$2 $value`$4"
-    }
-
-    Set-Content -Path "totp/features_config.h" -NoNewline -Value $featuresConfigContent
-    Set-Content -Path "totp/application.fam" -NoNewline -Value $appManifestContent
-}
-
 function Build-Run {
 function Build-Run {
     param (
     param (
-        [string]$FeaturesSuffix
+        [string]$FeaturesSuffix,
+        [string[]]$CppDefine
     )
     )
 
 
     foreach ($build_command in $build_commands) {
     foreach ($build_command in $build_commands) {
@@ -92,9 +48,15 @@ function Build-Run {
             Remove-Item "$build_path\*" -Recurse -Force
             Remove-Item "$build_path\*" -Recurse -Force
         }
         }
 
 
-        Features-Configure -set "TOTP_TARGET_FIRMWARE=$($build_command.FW_CDEF)"
+        $fbt_args = @($build_command.FbtSwitch, "COMPACT=1", "DEBUG=0", "VERBOSE=0", "fap_totp")
+        if ($CppDefine.Length -gt 0) {
+            $CppDefine | ForEach-Object {
+                $fbt_args += '-D'
+                $fbt_args += $_
+            }
+        }
 
 
-        ./fbt $build_command.FbtSwitch COMPACT=1 DEBUG=0 VERBOSE=0 fap_totp
+        Invoke-Expression -Command "./fbt.ps1 $fbt_args"
 
 
         $latest_dir = Get-LatestDirectory -Path $build_path
         $latest_dir = Get-LatestDirectory -Path $build_path
         $build_output_artifact = "build\$($build_command.ArtifactName -replace '{FEATURES_SUFFIX}',$FeaturesSuffix)"
         $build_output_artifact = "build\$($build_command.ArtifactName -replace '{FEATURES_SUFFIX}',$FeaturesSuffix)"
@@ -105,17 +67,12 @@ function Build-Run {
 }
 }
 
 
 Write-Information 'Building with all the features enables'
 Write-Information 'Building with all the features enables'
-Features-Configure -enable TOTP_BADBT_TYPE_ENABLED,TOTP_AUTOMATION_ICONS_ENABLED
 Build-Run -FeaturesSuffix ''
 Build-Run -FeaturesSuffix ''
 
 
 Write-Information 'Building with BadBT but without BadBT icon'
 Write-Information 'Building with BadBT but without BadBT icon'
-Features-Configure -disable TOTP_AUTOMATION_ICONS_ENABLED
-Build-Run -FeaturesSuffix '_badbt-wo-icon'
+Build-Run -FeaturesSuffix '_badbt-wo-icon' -CppDefine TOTP_NO_AUTOMATION_ICONS
 
 
 Write-Information 'Building without BadBT'
 Write-Information 'Building without BadBT'
-Features-Configure -disable TOTP_BADBT_TYPE_ENABLED,TOTP_AUTOMATION_ICONS_ENABLED
-Build-Run -FeaturesSuffix '_no-badbt'
-
-Features-Configure -enable TOTP_BADBT_TYPE_ENABLED,TOTP_AUTOMATION_ICONS_ENABLED -set TOTP_TARGET_FIRMWARE=TOTP_FIRMWARE_XTREME
+Build-Run -FeaturesSuffix '_no-badbt' -CppDefine TOTP_NO_BADBT_TYPE,TOTP_NO_AUTOMATION_ICONS
 
 
 Pop-Location
 Pop-Location

+ 28 - 1
fbt.ps1

@@ -2,16 +2,20 @@ Push-Location $PSScriptRoot
 
 
 $firmware_path = ""
 $firmware_path = ""
 $firmware_name = ""
 $firmware_name = ""
+$FW_CDEF = ""
 if (('official-dev', 'off-dev', 'od', 'unleashed', 'un', 'u').Contains($args[0])) {
 if (('official-dev', 'off-dev', 'od', 'unleashed', 'un', 'u').Contains($args[0])) {
     $firmware_path = "flipperzero-firmware_official_dev"
     $firmware_path = "flipperzero-firmware_official_dev"
     $firmware_name = "Official Dev"
     $firmware_name = "Official Dev"
+    $FW_CDEF = "TOTP_FIRMWARE_OFFICIAL_DEV"
 }
 }
 elseif (('official-stable', 'off-stbl', 'os').Contains($args[0])) {
 elseif (('official-stable', 'off-stbl', 'os').Contains($args[0])) {
     $firmware_path = "flipperzero-firmware_official_stable"
     $firmware_path = "flipperzero-firmware_official_stable"
     $firmware_name = "Official Stable"
     $firmware_name = "Official Stable"
+    $FW_CDEF = "TOTP_FIRMWARE_OFFICIAL_STABLE"
 } elseif (('xtreme', 'xt', 'x').Contains($args[0])) {
 } elseif (('xtreme', 'xt', 'x').Contains($args[0])) {
     $firmware_path = "flipperzero-firmware_xtreme"
     $firmware_path = "flipperzero-firmware_xtreme"
     $firmware_name = "Xtreme"
     $firmware_name = "Xtreme"
+    $FW_CDEF = "TOTP_FIRMWARE_XTREME"
 }
 }
 else {
 else {
     throw "Unable to recognize which firmware to use"
     throw "Unable to recognize which firmware to use"
@@ -22,6 +26,29 @@ Write-Host "Using $firmware_name firmware to run FBT"
 $commandline_scons = "$firmware_path\site_scons\commandline.scons"
 $commandline_scons = "$firmware_path\site_scons\commandline.scons"
 ((Get-Content -Path $commandline_scons -Raw) -replace 'applications_user','..') | Set-Content -Path $commandline_scons -NoNewline
 ((Get-Content -Path $commandline_scons -Raw) -replace 'applications_user','..') | Set-Content -Path $commandline_scons -NoNewline
 
 
+$i = 1
+$args_ls = @()
+$cpp_defines = @("(`"TOTP_TARGET_FIRMWARE`", `"$FW_CDEF`")")
+while ($i -lt $args.Count) {
+    if ($args[$i] -eq '-D') {
+        $define = $args[$i + 1].Split('=')
+        if ($define.Length -gt 1) {
+            $cpp_defines += "(`"$($define[0])`", `"$($define[1])`")"
+        } else {
+            $cpp_defines += "`"$($define[0])`""
+        }
+        $i = $i + 2
+    } else {
+        $args_ls += $args[$i]
+        $i = $i + 1
+    }
+}
+
+if ($cpp_defines.Length -gt 0) {
+    $cc_scons = "$firmware_path\site_scons\cc.scons"
+    (Get-Content -Path $cc_scons -Raw) -replace "(CPPDEFINES\s*=\s*\[)(([^]]\r?\n?)*)(\])", "`$1`"_GNU_SOURCE`", $($cpp_defines -join ", ")`$4" | Set-Content -Path $cc_scons -NoNewline
+}
+
 $builtin_totp_path = "$firmware_path\applications\external\totp"
 $builtin_totp_path = "$firmware_path\applications\external\totp"
 if ((Test-Path -Path $builtin_totp_path) -eq $True) {
 if ((Test-Path -Path $builtin_totp_path) -eq $True) {
     Remove-Item $builtin_totp_path -Recurse
     Remove-Item $builtin_totp_path -Recurse
@@ -29,7 +56,7 @@ if ((Test-Path -Path $builtin_totp_path) -eq $True) {
 
 
 Push-Location $firmware_path
 Push-Location $firmware_path
 
 
-./fbt $args[1..($args.Length - 1)]
+./fbt $args_ls
 
 
 Pop-Location
 Pop-Location
 Pop-Location
 Pop-Location

+ 0 - 2
totp/application.fam

@@ -11,9 +11,7 @@ App(
         "storage",
         "storage",
         "input", 
         "input", 
         "notification",
         "notification",
-#ifdef TOTP_BADBT_TYPE_ENABLED
         "bt"
         "bt"
-#endif
     ],
     ],
     stack_size=2 * 1024,
     stack_size=2 * 1024,
     order=20,
     order=20,

+ 1 - 1
totp/cli/commands/reset/reset.c

@@ -1,7 +1,7 @@
 #include "reset.h"
 #include "reset.h"
 
 
 #include <stdlib.h>
 #include <stdlib.h>
-#include <furi/furi.h>
+#include <furi/core/string.h>
 #include "../../cli_helpers.h"
 #include "../../cli_helpers.h"
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
 
 

+ 6 - 1
totp/features_config.h

@@ -1,8 +1,12 @@
 // Include Bluetooth token input automation
 // Include Bluetooth token input automation
+#ifndef TOTP_NO_BADBT_TYPE
 #define TOTP_BADBT_TYPE_ENABLED
 #define TOTP_BADBT_TYPE_ENABLED
+#endif
 
 
 // Include token input automation icons on the main screen
 // Include token input automation icons on the main screen
+#ifndef TOTP_NO_AUTOMATION_ICONS
 #define TOTP_AUTOMATION_ICONS_ENABLED
 #define TOTP_AUTOMATION_ICONS_ENABLED
+#endif
 
 
 // List of compatible firmwares
 // List of compatible firmwares
 #define TOTP_FIRMWARE_OFFICIAL_STABLE (1)
 #define TOTP_FIRMWARE_OFFICIAL_STABLE (1)
@@ -10,7 +14,8 @@
 #define TOTP_FIRMWARE_XTREME (3)
 #define TOTP_FIRMWARE_XTREME (3)
 // End of list
 // End of list
 
 
-// Target firmware to build for
+// Target firmware to build for.
 #ifndef TOTP_TARGET_FIRMWARE
 #ifndef TOTP_TARGET_FIRMWARE
+// Defaulting to Xtreme if not previously defined
 #define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME
 #define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME
 #endif
 #endif

+ 3 - 0
totp/lib/polyfills/strnlen.h

@@ -1,3 +1,6 @@
+#pragma once
+#pragma weak strnlen
+
 #include <stddef.h>
 #include <stddef.h>
 
 
 size_t strnlen(const char* s, size_t maxlen);
 size_t strnlen(const char* s, size_t maxlen);

+ 1 - 1
totp/services/config/config.c

@@ -57,7 +57,7 @@ static char* totp_config_file_backup_i(Storage* storage) {
     }
     }
 
 
     if(backup_file_exists ||
     if(backup_file_exists ||
-       !storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) == FSE_OK) {
+       storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) != FSE_OK) {
         FURI_LOG_E(LOGGING_TAG, "Unable to take a backup");
         FURI_LOG_E(LOGGING_TAG, "Unable to take a backup");
         free(backup_path);
         free(backup_path);
         return NULL;
         return NULL;

+ 0 - 1
totp/services/config/config.h

@@ -1,7 +1,6 @@
 #pragma once
 #pragma once
 
 
 #include <flipper_format/flipper_format.h>
 #include <flipper_format/flipper_format.h>
-#include <furi.h>
 #include "../../types/plugin_state.h"
 #include "../../types/plugin_state.h"
 #include "../../types/token_info.h"
 #include "../../types/token_info.h"
 #include "constants.h"
 #include "constants.h"

+ 3 - 2
totp/services/crypto/crypto.c

@@ -1,6 +1,7 @@
 #include "crypto.h"
 #include "crypto.h"
-#include <furi.h>
-#include <furi_hal.h>
+#include <furi_hal_crypto.h>
+#include <furi_hal_random.h>
+#include <furi_hal_version.h>
 #include "../config/config.h"
 #include "../config/config.h"
 #include "../../types/common.h"
 #include "../../types/common.h"
 #include "memset_s.h"
 #include "memset_s.h"

+ 1 - 3
totp/services/totp/totp.c

@@ -1,15 +1,13 @@
 #include "totp.h"
 #include "totp.h"
 
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdint.h>
-#include <string.h>
 #include <math.h>
 #include <math.h>
+#include <timezone_utils.h>
 #include "../hmac/hmac_sha1.h"
 #include "../hmac/hmac_sha1.h"
 #include "../hmac/hmac_sha256.h"
 #include "../hmac/hmac_sha256.h"
 #include "../hmac/hmac_sha512.h"
 #include "../hmac/hmac_sha512.h"
 #include "../hmac/byteswap.h"
 #include "../hmac/byteswap.h"
-#include "../../lib/timezone_utils/timezone_utils.h"
 
 
 #define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE
 #define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE
 
 

+ 0 - 7
totp/totp_app.c

@@ -1,10 +1,7 @@
-#include <furi.h>
-#include <furi_hal.h>
 #include <gui/gui.h>
 #include <gui/gui.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <dialogs/dialogs.h>
 #include <dialogs/dialogs.h>
 #include <stdlib.h>
 #include <stdlib.h>
-#include <flipper_format/flipper_format.h>
 #include <notification/notification.h>
 #include <notification/notification.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
@@ -105,10 +102,6 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
     }
     }
 
 
     plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-    if(plugin_state->mutex == NULL) {
-        FURI_LOG_E(LOGGING_TAG, "Cannot create mutex\r\n");
-        return false;
-    }
 
 
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #ifdef TOTP_BADBT_TYPE_ENABLED
     if(plugin_state->automation_method & AutomationMethodBadBt) {
     if(plugin_state->automation_method & AutomationMethodBadBt) {

+ 0 - 2
totp/types/token_info.c

@@ -1,9 +1,7 @@
 #include "token_info.h"
 #include "token_info.h"
-#include <furi_hal.h>
 #include <base32.h>
 #include <base32.h>
 #include <base64.h>
 #include <base64.h>
 #include <memset_s.h>
 #include <memset_s.h>
-#include <strnlen.h>
 #include "common.h"
 #include "common.h"
 #include "../services/crypto/crypto.h"
 #include "../services/crypto/crypto.h"
 
 

+ 1 - 1
totp/types/token_info.h

@@ -2,7 +2,7 @@
 
 
 #include <inttypes.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdbool.h>
-#include <furi/furi.h>
+#include <furi/core/string.h>
 
 
 #define TOTP_TOKEN_DURATION_DEFAULT (30)
 #define TOTP_TOKEN_DURATION_DEFAULT (30)
 
 

+ 0 - 1
totp/ui/scenes/add_new_token/totp_input_text.c

@@ -1,6 +1,5 @@
 #include "totp_input_text.h"
 #include "totp_input_text.h"
 #include <gui/view_i.h>
 #include <gui/view_i.h>
-#include "../../../lib/polyfills/strnlen.h"
 
 
 void view_draw(View* view, Canvas* canvas) {
 void view_draw(View* view, Canvas* canvas) {
     furi_assert(view);
     furi_assert(view);

+ 0 - 2
totp/ui/scenes/add_new_token/totp_scene_add_new_token.h

@@ -1,8 +1,6 @@
 #pragma once
 #pragma once
 
 
 #include <gui/gui.h>
 #include <gui/gui.h>
-#include <furi.h>
-#include <furi_hal.h>
 #include "../../../types/plugin_state.h"
 #include "../../../types/plugin_state.h"
 #include "../../../types/plugin_event.h"
 #include "../../../types/plugin_event.h"
 
 

+ 69 - 127
totp/ui/scenes/generate_token/totp_scene_generate_token.c

@@ -2,19 +2,16 @@
 #include <notification/notification.h>
 #include <notification/notification.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
 #include <totp_icons.h>
 #include <totp_icons.h>
+#include <roll_value.h>
 #include "totp_scene_generate_token.h"
 #include "totp_scene_generate_token.h"
 #include "../../../types/token_info.h"
 #include "../../../types/token_info.h"
 #include "../../../types/common.h"
 #include "../../../types/common.h"
 #include "../../constants.h"
 #include "../../constants.h"
-#include "../../../services/totp/totp.h"
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
-#include "../../../services/crypto/crypto.h"
-#include "../../../services/convert/convert.h"
-#include "../../../lib/polyfills/memset_s.h"
-#include "../../../lib/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 "../../../features_config.h"
 #include "../../../features_config.h"
+#include "../../../workers/generate_totp_code/generate_totp_code.h"
 #include "../../../workers/usb_type_code/usb_type_code.h"
 #include "../../../workers/usb_type_code/usb_type_code.h"
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #include "../../../workers/bt_type_code/bt_type_code.h"
 #include "../../../workers/bt_type_code/bt_type_code.h"
@@ -23,18 +20,18 @@
 
 
 #define PROGRESS_BAR_MARGIN (3)
 #define PROGRESS_BAR_MARGIN (3)
 #define PROGRESS_BAR_HEIGHT (4)
 #define PROGRESS_BAR_HEIGHT (4)
-static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
 
 
 typedef struct {
 typedef struct {
     uint16_t current_token_index;
     uint16_t current_token_index;
     char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
     char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
-    bool need_token_update;
     TokenInfo* current_token;
     TokenInfo* current_token;
-    uint32_t last_token_gen_time;
     TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
     TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
     NotificationMessage const** notification_sequence_new_token;
     NotificationMessage const** notification_sequence_new_token;
-    NotificationMessage const** notification_sequence_badusb;
+    NotificationMessage const** notification_sequence_automation;
     FuriMutex* last_code_update_sync;
     FuriMutex* last_code_update_sync;
+    TotpGenerateCodeWorkerContext* generate_code_worker_context;
+    uint8_t progress_bar_x;
+    uint8_t progress_bar_width;
 } SceneState;
 } SceneState;
 
 
 static const NotificationSequence*
 static const NotificationSequence*
@@ -80,7 +77,7 @@ static const NotificationSequence*
 
 
 static const NotificationSequence*
 static const NotificationSequence*
     get_notification_sequence_automation(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) {
+    if(scene_state->notification_sequence_automation == NULL) {
         uint8_t i = 0;
         uint8_t i = 0;
         uint8_t length = 3;
         uint8_t length = 3;
         if(plugin_state->notification_method & NotificationMethodVibro) {
         if(plugin_state->notification_method & NotificationMethodVibro) {
@@ -91,84 +88,46 @@ static const NotificationSequence*
             length += 6;
             length += 6;
         }
         }
 
 
-        scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length);
-        furi_check(scene_state->notification_sequence_badusb != NULL);
+        scene_state->notification_sequence_automation = malloc(sizeof(void*) * length);
+        furi_check(scene_state->notification_sequence_automation != NULL);
 
 
-        scene_state->notification_sequence_badusb[i++] = &message_blue_255;
+        scene_state->notification_sequence_automation[i++] = &message_blue_255;
         if(plugin_state->notification_method & NotificationMethodVibro) {
         if(plugin_state->notification_method & NotificationMethodVibro) {
-            scene_state->notification_sequence_badusb[i++] = &message_vibro_on;
+            scene_state->notification_sequence_automation[i++] = &message_vibro_on;
         }
         }
 
 
         if(plugin_state->notification_method & NotificationMethodSound) {
         if(plugin_state->notification_method & NotificationMethodSound) {
-            scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525
-            scene_state->notification_sequence_badusb[i++] = &message_delay_50;
-            scene_state->notification_sequence_badusb[i++] = &message_note_e4;
-            scene_state->notification_sequence_badusb[i++] = &message_delay_50;
-            scene_state->notification_sequence_badusb[i++] = &message_note_f3;
+            scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525
+            scene_state->notification_sequence_automation[i++] = &message_delay_50;
+            scene_state->notification_sequence_automation[i++] = &message_note_e4;
+            scene_state->notification_sequence_automation[i++] = &message_delay_50;
+            scene_state->notification_sequence_automation[i++] = &message_note_f3;
         }
         }
 
 
-        scene_state->notification_sequence_badusb[i++] = &message_delay_50;
+        scene_state->notification_sequence_automation[i++] = &message_delay_50;
 
 
         if(plugin_state->notification_method & NotificationMethodVibro) {
         if(plugin_state->notification_method & NotificationMethodVibro) {
-            scene_state->notification_sequence_badusb[i++] = &message_vibro_off;
+            scene_state->notification_sequence_automation[i++] = &message_vibro_off;
         }
         }
 
 
         if(plugin_state->notification_method & NotificationMethodSound) {
         if(plugin_state->notification_method & NotificationMethodSound) {
-            scene_state->notification_sequence_badusb[i++] = &message_sound_off;
+            scene_state->notification_sequence_automation[i++] = &message_sound_off;
         }
         }
 
 
-        scene_state->notification_sequence_badusb[i++] = NULL;
+        scene_state->notification_sequence_automation[i++] = NULL;
     }
     }
 
 
-    return (NotificationSequence*)scene_state->notification_sequence_badusb;
-}
-
-static void
-    int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
-    if(i_token_code == OTP_ERROR) {
-        memset(&str[0], '-', len);
-    } else {
-        if(algo == STEAM) {
-            for(uint8_t i = 0; i < len; i++) {
-                str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
-                i_token_code = i_token_code / 26;
-            }
-        } else {
-            for(int8_t i = len - 1; i >= 0; i--) {
-                str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
-                i_token_code = i_token_code / 10;
-            }
-        }
-    }
-
-    str[len] = '\0';
-}
-
-static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
-    switch(algo) {
-    case SHA1:
-    case STEAM:
-        return TOTP_ALGO_SHA1;
-    case SHA256:
-        return TOTP_ALGO_SHA256;
-    case SHA512:
-        return TOTP_ALGO_SHA512;
-    default:
-        break;
-    }
-
-    return NULL;
+    return (NotificationSequence*)scene_state->notification_sequence_automation;
 }
 }
 
 
 static void update_totp_params(PluginState* const plugin_state) {
 static void update_totp_params(PluginState* const plugin_state) {
     SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
     SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
 
 
     if(scene_state->current_token_index < plugin_state->tokens_count) {
     if(scene_state->current_token_index < plugin_state->tokens_count) {
-        TokenInfo* tokenInfo =
+        scene_state->current_token =
             list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
             list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
-
-        scene_state->need_token_update = true;
-        scene_state->current_token = tokenInfo;
+        totp_generate_code_worker_notify(
+            scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
     }
     }
 }
 }
 
 
@@ -194,6 +153,24 @@ static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_s
     }
     }
 }
 }
 
 
+static void on_new_token_code_generated(bool time_left, void* context) {
+    if(time_left) {
+        PluginState* plugin_state = context;
+        notification_message(
+            plugin_state->notification_app,
+            get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state));
+    }
+}
+
+static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) {
+    SceneState* scene_state = context;
+    scene_state->progress_bar_width =
+        (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
+    scene_state->progress_bar_x =
+        ((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - scene_state->progress_bar_width) >> 1) +
+        PROGRESS_BAR_MARGIN;
+}
+
 void totp_scene_generate_token_activate(
 void totp_scene_generate_token_activate(
     PluginState* plugin_state,
     PluginState* plugin_state,
     const GenerateTokenSceneContext* context) {
     const GenerateTokenSceneContext* context) {
@@ -231,15 +208,14 @@ void totp_scene_generate_token_activate(
     } else {
     } else {
         scene_state->current_token_index = context->current_token_index;
         scene_state->current_token_index = context->current_token_index;
     }
     }
-    scene_state->need_token_update = true;
+
     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);
 
 
     scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal);
     scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal);
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
         scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start(
         scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start(
-            &scene_state->last_code[0],
+            scene_state->last_code,
             TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
             TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
             scene_state->last_code_update_sync);
             scene_state->last_code_update_sync);
     }
     }
@@ -252,11 +228,28 @@ void totp_scene_generate_token_activate(
         }
         }
         totp_bt_type_code_worker_start(
         totp_bt_type_code_worker_start(
             plugin_state->bt_type_code_worker_context,
             plugin_state->bt_type_code_worker_context,
-            &scene_state->last_code[0],
+            scene_state->last_code,
             TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
             TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
             scene_state->last_code_update_sync);
             scene_state->last_code_update_sync);
     }
     }
 #endif
 #endif
+
+    scene_state->generate_code_worker_context = totp_generate_code_worker_start(
+        scene_state->last_code,
+        &scene_state->current_token,
+        scene_state->last_code_update_sync,
+        plugin_state->timezone_offset,
+        plugin_state->iv);
+
+    totp_generate_code_worker_set_code_generated_handler(
+        scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
+
+    totp_generate_code_worker_set_lifetime_changed_handler(
+        scene_state->generate_code_worker_context,
+        &on_code_lifetime_updated_generated,
+        scene_state);
+
+    update_totp_params(plugin_state);
 }
 }
 
 
 void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
 void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
@@ -278,54 +271,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
         return;
         return;
     }
     }
 
 
-    SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
-    FuriHalRtcDateTime curr_dt;
-    furi_hal_rtc_get_datetime(&curr_dt);
-    uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
-
-    bool is_new_token_time = curr_ts % scene_state->current_token->duration == 0;
-    if(is_new_token_time && scene_state->last_token_gen_time != curr_ts) {
-        scene_state->need_token_update = true;
-    }
-
-    if(scene_state->need_token_update) {
-        scene_state->need_token_update = false;
-        scene_state->last_token_gen_time = curr_ts;
-
-        const TokenInfo* tokenInfo = scene_state->current_token;
-
-        if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
-            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);
-
-            int_token_to_str(
-                totp_at(
-                    get_totp_algo_impl(tokenInfo->algo),
-                    key,
-                    key_length,
-                    curr_ts,
-                    plugin_state->timezone_offset,
-                    tokenInfo->duration),
-                scene_state->last_code,
-                tokenInfo->digits,
-                tokenInfo->algo);
-            memset_s(key, key_length, 0, key_length);
-            free(key);
-        } else {
-            furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever);
-            int_token_to_str(0, scene_state->last_code, tokenInfo->digits, tokenInfo->algo);
-        }
-
-        furi_mutex_release(scene_state->last_code_update_sync);
-
-        if(is_new_token_time) {
-            notification_message(
-                plugin_state->notification_app,
-                get_notification_sequence_new_token(plugin_state, scene_state));
-        }
-    }
+    const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
 
 
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
     uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
     uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
@@ -353,17 +299,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
 
 
     draw_totp_code(canvas, scene_state);
     draw_totp_code(canvas, scene_state);
 
 
-    const uint8_t TOKEN_LIFETIME = scene_state->current_token->duration;
-    float percentDone = (float)(TOKEN_LIFETIME - curr_ts % TOKEN_LIFETIME) / (float)TOKEN_LIFETIME;
-    uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * percentDone);
-    uint8_t barX =
-        ((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - barWidth) >> 1) + PROGRESS_BAR_MARGIN;
-
     canvas_draw_box(
     canvas_draw_box(
         canvas,
         canvas,
-        barX,
+        scene_state->progress_bar_x,
         SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
         SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
-        barWidth,
+        scene_state->progress_bar_width,
         PROGRESS_BAR_HEIGHT);
         PROGRESS_BAR_HEIGHT);
 
 
     if(plugin_state->tokens_count > 1) {
     if(plugin_state->tokens_count > 1) {
@@ -493,6 +433,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_generate_code_worker_stop(scene_state->generate_code_worker_context);
+
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
         totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
         totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
     }
     }
@@ -506,8 +448,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
         free(scene_state->notification_sequence_new_token);
         free(scene_state->notification_sequence_new_token);
     }
     }
 
 
-    if(scene_state->notification_sequence_badusb != NULL) {
-        free(scene_state->notification_sequence_badusb);
+    if(scene_state->notification_sequence_automation != NULL) {
+        free(scene_state->notification_sequence_automation);
     }
     }
 
 
     furi_mutex_free(scene_state->last_code_update_sync);
     furi_mutex_free(scene_state->last_code_update_sync);

+ 19 - 19
totp/workers/bt_type_code/bt_type_code.c

@@ -1,10 +1,11 @@
 #include "bt_type_code.h"
 #include "bt_type_code.h"
 #include <furi_hal_bt_hid.h>
 #include <furi_hal_bt_hid.h>
+#include <furi_hal_version.h>
 #include <bt/bt_service/bt_i.h>
 #include <bt/bt_service/bt_i.h>
 #include <storage/storage.h>
 #include <storage/storage.h>
 #include "../../types/common.h"
 #include "../../types/common.h"
 #include "../../types/token_info.h"
 #include "../../types/token_info.h"
-#include "../common.h"
+#include "../type-code-common.h"
 
 
 #define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
 #define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
 
 
@@ -16,15 +17,15 @@ static inline bool totp_type_code_worker_stop_requested() {
 static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) {
 static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) {
     uint8_t max_i;
     uint8_t max_i;
     size_t uid_size = furi_hal_version_uid_size();
     size_t uid_size = furi_hal_version_uid_size();
-    if(uid_size < 6) {
+    if(uid_size < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN) {
         max_i = uid_size;
         max_i = uid_size;
     } else {
     } else {
-        max_i = 6;
+        max_i = TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN;
     }
     }
 
 
     const uint8_t* uid = furi_hal_version_uid();
     const uint8_t* uid = furi_hal_version_uid();
     memcpy(mac, uid, max_i);
     memcpy(mac, uid, max_i);
-    for(uint8_t i = max_i; i < 6; i++) {
+    for(uint8_t i = max_i; i < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN; i++) {
         mac[i] = 0;
         mac[i] = 0;
     }
     }
 
 
@@ -39,23 +40,21 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
         i++;
         i++;
     } while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested());
     } while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested());
 
 
-    if(context->is_connected && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
+    if(context->is_connected &&
+       furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
         totp_type_code_worker_execute_automation(
         totp_type_code_worker_execute_automation(
             &furi_hal_bt_hid_kb_press,
             &furi_hal_bt_hid_kb_press,
             &furi_hal_bt_hid_kb_release,
             &furi_hal_bt_hid_kb_release,
-            context->string,
-            context->string_length,
+            context->code_buffer,
+            context->code_buffer_size,
             context->flags);
             context->flags);
-        furi_mutex_release(context->string_sync);
+        furi_mutex_release(context->code_buffer_sync);
     }
     }
 }
 }
 
 
 static int32_t totp_type_code_worker_callback(void* context) {
 static int32_t totp_type_code_worker_callback(void* context) {
     furi_check(context);
     furi_check(context);
     FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-    if(context_mutex == NULL) {
-        return 251;
-    }
 
 
     TotpBtTypeCodeWorkerContext* bt_context = context;
     TotpBtTypeCodeWorkerContext* bt_context = context;
 
 
@@ -92,13 +91,13 @@ static void connection_status_changed_callback(BtStatus status, void* context) {
 
 
 void totp_bt_type_code_worker_start(
 void totp_bt_type_code_worker_start(
     TotpBtTypeCodeWorkerContext* context,
     TotpBtTypeCodeWorkerContext* context,
-    char* code_buf,
-    uint8_t code_buf_length,
-    FuriMutex* code_buf_update_sync) {
+    char* code_buffer,
+    uint8_t code_buffer_size,
+    FuriMutex* code_buffer_sync) {
     furi_check(context != NULL);
     furi_check(context != NULL);
-    context->string = code_buf;
-    context->string_length = code_buf_length;
-    context->string_sync = code_buf_update_sync;
+    context->code_buffer = code_buffer;
+    context->code_buffer_size = code_buffer_size;
+    context->code_buffer_sync = code_buffer_sync;
     context->thread = furi_thread_alloc();
     context->thread = furi_thread_alloc();
     furi_thread_set_name(context->thread, "TOTPBtHidWorker");
     furi_thread_set_name(context->thread, "TOTPBtHidWorker");
     furi_thread_set_stack_size(context->thread, 1024);
     furi_thread_set_stack_size(context->thread, 1024);
@@ -137,7 +136,6 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
     bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH);
     bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH);
 
 
 #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
 #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
-    totp_type_code_worker_bt_set_app_mac(&context->bt_mac[0]);
     memcpy(
     memcpy(
         &context->previous_bt_name[0],
         &context->previous_bt_name[0],
         furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
         furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
@@ -148,8 +146,10 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
         TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN);
         TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN);
     char new_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
     char new_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
     snprintf(new_name, sizeof(new_name), "%s TOTP Auth", furi_hal_version_get_name_ptr());
     snprintf(new_name, sizeof(new_name), "%s TOTP Auth", furi_hal_version_get_name_ptr());
+    uint8_t new_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
+    totp_type_code_worker_bt_set_app_mac(new_bt_mac);
     furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, new_name);
     furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, new_name);
-    furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, context->bt_mac);
+    furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, new_bt_mac);
 #endif
 #endif
 
 
     if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) {
     if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) {

+ 13 - 12
totp/workers/bt_type_code/bt_type_code.h

@@ -1,8 +1,10 @@
 #pragma once
 #pragma once
 
 
 #include <stdlib.h>
 #include <stdlib.h>
-#include <furi/furi.h>
-#include <furi_hal.h>
+#include <furi/core/thread.h>
+#include <furi/core/mutex.h>
+#include <furi/core/string.h>
+#include <furi/core/kernel.h>
 #include <bt/bt_service/bt.h>
 #include <bt/bt_service/bt.h>
 #include "../../features_config.h"
 #include "../../features_config.h"
 
 
@@ -14,34 +16,33 @@
 typedef uint8_t TotpBtTypeCodeWorkerEvent;
 typedef uint8_t TotpBtTypeCodeWorkerEvent;
 
 
 typedef struct {
 typedef struct {
-    char* string;
-    uint8_t string_length;
+    char* code_buffer;
+    uint8_t code_buffer_size;
     uint8_t flags;
     uint8_t flags;
     FuriThread* thread;
     FuriThread* thread;
-    FuriMutex* string_sync;
+    FuriMutex* code_buffer_sync;
     Bt* bt;
     Bt* bt;
     bool is_advertising;
     bool is_advertising;
     bool is_connected;
     bool is_connected;
 #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
 #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
-    uint8_t bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
     char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
     char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
     uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
     uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
 #endif
 #endif
 } TotpBtTypeCodeWorkerContext;
 } TotpBtTypeCodeWorkerContext;
 
 
 enum TotpBtTypeCodeWorkerEvents {
 enum TotpBtTypeCodeWorkerEvents {
-    TotpBtTypeCodeWorkerEventReserved = 0b0000,
-    TotpBtTypeCodeWorkerEventStop = 0b0100,
-    TotpBtTypeCodeWorkerEventType = 0b1000
+    TotpBtTypeCodeWorkerEventReserved = 0b00,
+    TotpBtTypeCodeWorkerEventStop = 0b01,
+    TotpBtTypeCodeWorkerEventType = 0b10
 };
 };
 
 
 TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
 TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
 void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
 void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
 void totp_bt_type_code_worker_start(
 void totp_bt_type_code_worker_start(
     TotpBtTypeCodeWorkerContext* context,
     TotpBtTypeCodeWorkerContext* context,
-    char* code_buf,
-    uint8_t code_buf_length,
-    FuriMutex* code_buf_update_sync);
+    char* code_buffer,
+    uint8_t code_buffer_size,
+    FuriMutex* code_buffer_sync);
 void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
 void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
 void totp_bt_type_code_worker_notify(
 void totp_bt_type_code_worker_notify(
     TotpBtTypeCodeWorkerContext* context,
     TotpBtTypeCodeWorkerContext* context,

+ 181 - 0
totp/workers/generate_totp_code/generate_totp_code.c

@@ -0,0 +1,181 @@
+#include "generate_totp_code.h"
+#include "../../services/crypto/crypto.h"
+#include "../../services/totp/totp.h"
+#include "../../services/convert/convert.h"
+#include <furi_hal_rtc.h>
+#include <memset_s.h>
+
+#define ONE_SEC_MS (1000)
+
+static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
+
+static void
+    int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
+    str[len] = '\0';
+    if(i_token_code == OTP_ERROR) {
+        memset(&str[0], '-', len);
+    } else {
+        if(algo == STEAM) {
+            for(uint8_t i = 0; i < len; i++) {
+                str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
+                i_token_code = i_token_code / 26;
+            }
+        } else {
+            for(int8_t i = len - 1; i >= 0; i--) {
+                str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
+                i_token_code = i_token_code / 10;
+            }
+        }
+    }
+}
+
+static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
+    switch(algo) {
+    case SHA1:
+    case STEAM:
+        return TOTP_ALGO_SHA1;
+    case SHA256:
+        return TOTP_ALGO_SHA256;
+    case SHA512:
+        return TOTP_ALGO_SHA512;
+    default:
+        break;
+    }
+
+    return NULL;
+}
+
+static void generate_totp_code(
+    TotpGenerateCodeWorkerContext* context,
+    const TokenInfo* token_info,
+    uint32_t current_ts) {
+    if(token_info->token != NULL && token_info->token_length > 0) {
+        size_t key_length;
+        uint8_t* key = totp_crypto_decrypt(
+            token_info->token, token_info->token_length, context->iv, &key_length);
+
+        int_token_to_str(
+            totp_at(
+                get_totp_algo_impl(token_info->algo),
+                key,
+                key_length,
+                current_ts,
+                context->timezone_offset,
+                token_info->duration),
+            context->code_buffer,
+            token_info->digits,
+            token_info->algo);
+        memset_s(key, key_length, 0, key_length);
+        free(key);
+    } else {
+        int_token_to_str(0, context->code_buffer, token_info->digits, token_info->algo);
+    }
+}
+
+static int32_t totp_generate_worker_callback(void* context) {
+    furi_check(context);
+
+    TotpGenerateCodeWorkerContext* t_context = context;
+
+    while(true) {
+        uint32_t flags = furi_thread_flags_wait(
+            TotpGenerateCodeWorkerEventStop | TotpGenerateCodeWorkerEventForceUpdate,
+            FuriFlagWaitAny,
+            ONE_SEC_MS);
+
+        if(flags ==
+           (uint32_t)
+               FuriFlagErrorTimeout) { // If timeout, consider as no error, as we expect this and can handle gracefully
+            flags = 0;
+        }
+
+        furi_check((flags & FuriFlagError) == 0); //-V562
+
+        if(flags & TotpGenerateCodeWorkerEventStop) break;
+
+        const TokenInfo* token_info = *(t_context->token_info);
+        if(token_info == NULL) {
+            continue;
+        }
+
+        uint32_t curr_ts = furi_hal_rtc_get_timestamp();
+
+        bool time_left = false;
+        if(flags & TotpGenerateCodeWorkerEventForceUpdate ||
+           (time_left = (curr_ts % token_info->duration) == 0)) {
+            if(furi_mutex_acquire(t_context->code_buffer_sync, FuriWaitForever) == FuriStatusOk) {
+                generate_totp_code(t_context, token_info, curr_ts);
+                curr_ts = furi_hal_rtc_get_timestamp();
+                furi_mutex_release(t_context->code_buffer_sync);
+                if(t_context->on_new_code_generated_handler != NULL) {
+                    (*(t_context->on_new_code_generated_handler))(
+                        time_left, t_context->on_new_code_generated_handler_context);
+                }
+            }
+        }
+
+        if(t_context->on_code_lifetime_changed_handler != NULL) {
+            (*(t_context->on_code_lifetime_changed_handler))(
+                (float)(token_info->duration - curr_ts % token_info->duration) /
+                    (float)token_info->duration,
+                t_context->on_code_lifetime_changed_handler_context);
+        }
+    }
+
+    return 0;
+}
+
+TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
+    char* code_buffer,
+    TokenInfo** token_info,
+    FuriMutex* code_buffer_sync,
+    float timezone_offset,
+    uint8_t* iv) {
+    TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
+    furi_check(context != NULL);
+    context->code_buffer = code_buffer;
+    context->token_info = token_info;
+    context->code_buffer_sync = code_buffer_sync;
+    context->timezone_offset = timezone_offset;
+    context->iv = iv;
+    context->thread = furi_thread_alloc();
+    furi_thread_set_name(context->thread, "TOTPGenerateWorker");
+    furi_thread_set_stack_size(context->thread, 2048);
+    furi_thread_set_context(context->thread, context);
+    furi_thread_set_callback(context->thread, totp_generate_worker_callback);
+    furi_thread_start(context->thread);
+    return context;
+}
+
+void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context) {
+    furi_check(context != NULL);
+    furi_thread_flags_set(furi_thread_get_id(context->thread), TotpGenerateCodeWorkerEventStop);
+    furi_thread_join(context->thread);
+    furi_thread_free(context->thread);
+    free(context);
+}
+
+void totp_generate_code_worker_notify(
+    TotpGenerateCodeWorkerContext* context,
+    TotpGenerateCodeWorkerEvent event) {
+    furi_check(context != NULL);
+    furi_thread_flags_set(furi_thread_get_id(context->thread), event);
+}
+
+void totp_generate_code_worker_set_code_generated_handler(
+    TotpGenerateCodeWorkerContext* context,
+    TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
+    void* on_new_code_generated_handler_context) {
+    furi_check(context != NULL);
+    context->on_new_code_generated_handler = on_new_code_generated_handler;
+    context->on_new_code_generated_handler_context = on_new_code_generated_handler_context;
+}
+
+void totp_generate_code_worker_set_lifetime_changed_handler(
+    TotpGenerateCodeWorkerContext* context,
+    TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
+    void* on_code_lifetime_changed_handler_context) {
+    furi_check(context != NULL);
+    context->on_code_lifetime_changed_handler = on_code_lifetime_changed_handler;
+    context->on_code_lifetime_changed_handler_context = on_code_lifetime_changed_handler_context;
+}

+ 49 - 0
totp/workers/generate_totp_code/generate_totp_code.h

@@ -0,0 +1,49 @@
+#pragma once
+
+#include <stdlib.h>
+#include <furi/core/thread.h>
+#include <furi/core/mutex.h>
+#include "../../types/token_info.h"
+
+typedef uint8_t TotpGenerateCodeWorkerEvent;
+
+typedef void (*TOTP_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context);
+typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
+
+typedef struct {
+    char* code_buffer;
+    FuriThread* thread;
+    FuriMutex* code_buffer_sync;
+    TokenInfo** token_info;
+    float timezone_offset;
+    uint8_t* iv;
+    TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
+    void* on_new_code_generated_handler_context;
+    TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
+    void* on_code_lifetime_changed_handler_context;
+} TotpGenerateCodeWorkerContext;
+
+enum TotGenerateCodeWorkerEvents {
+    TotpGenerateCodeWorkerEventReserved = 0b00,
+    TotpGenerateCodeWorkerEventStop = 0b01,
+    TotpGenerateCodeWorkerEventForceUpdate = 0b10
+};
+
+TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
+    char* code_buffer,
+    TokenInfo** token_info,
+    FuriMutex* code_buffer_sync,
+    float timezone_offset,
+    uint8_t* iv);
+void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context);
+void totp_generate_code_worker_notify(
+    TotpGenerateCodeWorkerContext* context,
+    TotpGenerateCodeWorkerEvent event);
+void totp_generate_code_worker_set_code_generated_handler(
+    TotpGenerateCodeWorkerContext* context,
+    TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
+    void* on_new_code_generated_handler_context);
+void totp_generate_code_worker_set_lifetime_changed_handler(
+    TotpGenerateCodeWorkerContext* context,
+    TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
+    void* on_code_lifetime_changed_handler_context);

+ 8 - 8
totp/workers/common.c → totp/workers/type-code-common.c

@@ -1,6 +1,6 @@
-#include "common.h"
-#include <furi/furi.h>
-#include <furi_hal.h>
+#include "type-code-common.h"
+#include <furi_hal_usb_hid.h>
+#include <furi/core/kernel.h>
 #include "../../services/convert/convert.h"
 #include "../../services/convert/convert.h"
 
 
 static const uint8_t hid_number_keys[] = {
 static const uint8_t hid_number_keys[] = {
@@ -42,18 +42,18 @@ static void totp_type_code_worker_press_key(
 void totp_type_code_worker_execute_automation(
 void totp_type_code_worker_execute_automation(
     TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
-    const char* string,
-    uint8_t string_length,
+    const char* code_buffer,
+    uint8_t code_buffer_size,
     TokenAutomationFeature features) {
     TokenAutomationFeature features) {
     furi_delay_ms(500);
     furi_delay_ms(500);
     uint8_t i = 0;
     uint8_t i = 0;
     totp_type_code_worker_press_key(
     totp_type_code_worker_press_key(
         HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
         HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
 
 
-    while(i < string_length && string[i] != 0) {
-        uint8_t char_index = CONVERT_CHAR_TO_DIGIT(string[i]);
+    while(i < code_buffer_size && code_buffer[i] != 0) {
+        uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]);
         if(char_index > 9) {
         if(char_index > 9) {
-            char_index = string[i] - 0x41 + 10;
+            char_index = code_buffer[i] - 0x41 + 10;
         }
         }
 
 
         if(char_index > 35) break;
         if(char_index > 35) break;

+ 2 - 2
totp/workers/common.h → totp/workers/type-code-common.h

@@ -7,6 +7,6 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
 void totp_type_code_worker_execute_automation(
 void totp_type_code_worker_execute_automation(
     TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
     TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
-    const char* string,
-    uint8_t string_length,
+    const char* code_buffer,
+    uint8_t code_buffer_size,
     TokenAutomationFeature features);
     TokenAutomationFeature features);

+ 12 - 14
totp/workers/usb_type_code/usb_type_code.c

@@ -1,7 +1,8 @@
 #include "usb_type_code.h"
 #include "usb_type_code.h"
+#include <furi_hal_usb_hid.h>
 #include "../../services/convert/convert.h"
 #include "../../services/convert/convert.h"
 #include "../../types/token_info.h"
 #include "../../types/token_info.h"
-#include "../common.h"
+#include "../type-code-common.h"
 
 
 static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
 static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
     if(context->usb_mode_prev != NULL) {
     if(context->usb_mode_prev != NULL) {
@@ -25,14 +26,14 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
     } while(!furi_hal_hid_is_connected() && i < 100 && !totp_type_code_worker_stop_requested());
     } while(!furi_hal_hid_is_connected() && i < 100 && !totp_type_code_worker_stop_requested());
 
 
     if(furi_hal_hid_is_connected() &&
     if(furi_hal_hid_is_connected() &&
-       furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
+       furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
         totp_type_code_worker_execute_automation(
         totp_type_code_worker_execute_automation(
             &furi_hal_hid_kb_press,
             &furi_hal_hid_kb_press,
             &furi_hal_hid_kb_release,
             &furi_hal_hid_kb_release,
-            context->string,
-            context->string_length,
+            context->code_buffer,
+            context->code_buffer_size,
             context->flags);
             context->flags);
-        furi_mutex_release(context->string_sync);
+        furi_mutex_release(context->code_buffer_sync);
 
 
         furi_delay_ms(100);
         furi_delay_ms(100);
     }
     }
@@ -43,9 +44,6 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
 static int32_t totp_type_code_worker_callback(void* context) {
 static int32_t totp_type_code_worker_callback(void* context) {
     furi_check(context);
     furi_check(context);
     FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-    if(context_mutex == NULL) {
-        return 251;
-    }
 
 
     while(true) {
     while(true) {
         uint32_t flags = furi_thread_flags_wait(
         uint32_t flags = furi_thread_flags_wait(
@@ -70,14 +68,14 @@ static int32_t totp_type_code_worker_callback(void* context) {
 }
 }
 
 
 TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
 TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
-    char* code_buf,
-    uint8_t code_buf_length,
-    FuriMutex* code_buf_update_sync) {
+    char* code_buffer,
+    uint8_t code_buffer_size,
+    FuriMutex* code_buffer_sync) {
     TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
     TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
     furi_check(context != NULL);
     furi_check(context != NULL);
-    context->string = code_buf;
-    context->string_length = code_buf_length;
-    context->string_sync = code_buf_update_sync;
+    context->code_buffer = code_buffer;
+    context->code_buffer_size = code_buffer_size;
+    context->code_buffer_sync = code_buffer_sync;
     context->thread = furi_thread_alloc();
     context->thread = furi_thread_alloc();
     context->usb_mode_prev = NULL;
     context->usb_mode_prev = NULL;
     furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
     furi_thread_set_name(context->thread, "TOTPUsbHidWorker");

+ 11 - 8
totp/workers/usb_type_code/usb_type_code.h

@@ -1,17 +1,20 @@
 #pragma once
 #pragma once
 
 
 #include <stdlib.h>
 #include <stdlib.h>
-#include <furi/furi.h>
-#include <furi_hal.h>
+#include <furi/core/thread.h>
+#include <furi/core/mutex.h>
+#include <furi/core/kernel.h>
+#include <furi/core/check.h>
+#include <furi_hal_usb.h>
 
 
 typedef uint8_t TotpUsbTypeCodeWorkerEvent;
 typedef uint8_t TotpUsbTypeCodeWorkerEvent;
 
 
 typedef struct {
 typedef struct {
-    char* string;
-    uint8_t string_length;
+    char* code_buffer;
+    uint8_t code_buffer_size;
     uint8_t flags;
     uint8_t flags;
     FuriThread* thread;
     FuriThread* thread;
-    FuriMutex* string_sync;
+    FuriMutex* code_buffer_sync;
     FuriHalUsbInterface* usb_mode_prev;
     FuriHalUsbInterface* usb_mode_prev;
 } TotpUsbTypeCodeWorkerContext;
 } TotpUsbTypeCodeWorkerContext;
 
 
@@ -22,9 +25,9 @@ enum TotpUsbTypeCodeWorkerEvents {
 };
 };
 
 
 TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
 TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
-    char* code_buf,
-    uint8_t code_buf_length,
-    FuriMutex* code_buf_update_sync);
+    char* code_buffer,
+    uint8_t code_buffer_size,
+    FuriMutex* code_buffer_sync);
 void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
 void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
 void totp_usb_type_code_worker_notify(
 void totp_usb_type_code_worker_notify(
     TotpUsbTypeCodeWorkerContext* context,
     TotpUsbTypeCodeWorkerContext* context,