mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 14:58:36 -07:00
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -2,4 +2,4 @@
|
|||||||
* @xMasterX
|
* @xMasterX
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
/assets/resources/infrared/ @xMasterX @amec0e
|
/assets/resources/infrared/assets/ @amec0e @Leptopt1los @xMasterX
|
||||||
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,7 +1,24 @@
|
|||||||
## New changes
|
## New changes
|
||||||
* SubGHz: Support for Ebyte E07 module power amp switch (works with TehRabbitt's Flux Capacitor Board) (by @Sil333033) (PR #559 by @Z3BRO) -> Remade by @xMasterX
|
* SubGHz: Support for Ebyte E07 module power amp switch (works with TehRabbitt's Flux Capacitor Board) (by @Sil333033) (PR #559 by @Z3BRO) -> Remade by @xMasterX -> Driver code fixed and reworked by @gid9798
|
||||||
|
* Infrared: Update universal remote assets (by @amec0e | PR #570)
|
||||||
|
* Infrared: Update universal AC asset (by @Leptopt1los | PR #569)
|
||||||
|
* Plugins: Add * in NFC Maker keyboard (hold `.`)
|
||||||
|
* Plugins: Update TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||||
* Plugins: Update ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder)
|
* Plugins: Update ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder)
|
||||||
* Plugins: Update ESP32-CAM -> Camera Suite [(by CodyTolene)](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite) -> (PR #562 by @CodyTolene)
|
* Plugins: Update ESP32-CAM -> Camera Suite [(by CodyTolene)](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite) -> (PR #562 by @CodyTolene)
|
||||||
|
* OFW PR 2949: IR: buttons move feature rework (by nminaylov)
|
||||||
|
* OFW PR 2941: FDX-B temperature now uses system units (by Astrrra)
|
||||||
|
* OFW: fbtenv: add additional environ variable to control execution flow
|
||||||
|
* OFW: NFC CLI: Fix multiple apdu commands from not working when one of them gives an empty response
|
||||||
|
* OFW: NFC: Fix MFC key invalidation
|
||||||
|
* OFW: Rename Applications to Apps
|
||||||
|
* OFW: Fix about screen
|
||||||
|
* OFW: change FuriThreadPriorityIsr to 31 (configMAX_PRIORITIES-1)
|
||||||
|
* OFW: External apps icounter
|
||||||
|
* OFW: Overly missed feature: Infrared: move button (change button order in a remote)
|
||||||
|
* OFW: Move U2F path to ext
|
||||||
|
* OFW: New RTC flags in device info
|
||||||
|
* OFW: Backlight notification fix
|
||||||
* OFW: Fix fbtenv restore
|
* OFW: Fix fbtenv restore
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|||||||
@@ -114,9 +114,10 @@ Encoders made by @assasinfil & @xMasterX:
|
|||||||
The majority of this project is developed and maintained by me, @xMasterX.
|
The majority of this project is developed and maintained by me, @xMasterX.
|
||||||
I'm unemployed, and the only income I receive is from your donations.
|
I'm unemployed, and the only income I receive is from your donations.
|
||||||
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
|
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
|
||||||
- @assasinfil - SubGHz
|
- @gid9798 - SubGHz, Plugins, many other things
|
||||||
|
- @assasinfil - SubGHz protocols
|
||||||
- @Svaarich - UI design and animations
|
- @Svaarich - UI design and animations
|
||||||
- @Amec0e - Infrared assets
|
- @amec0e & @Leptopt1los - Infrared assets
|
||||||
- Community moderators in Telegram, Discord, and Reddit
|
- Community moderators in Telegram, Discord, and Reddit
|
||||||
- And of course our GitHub community. Your PRs are a very important part of this firmware and open-source development.
|
- And of course our GitHub community. Your PRs are a very important part of this firmware and open-source development.
|
||||||
|
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ static char char_to_uppercase(const char letter) {
|
|||||||
return 0x5C;
|
return 0x5C;
|
||||||
} else if(letter == '\'') {
|
} else if(letter == '\'') {
|
||||||
return 0x60;
|
return 0x60;
|
||||||
|
} else if(letter == '.') {
|
||||||
|
return 0x2A;
|
||||||
} else if(char_is_lowercase(letter)) {
|
} else if(char_is_lowercase(letter)) {
|
||||||
return (letter - 0x20);
|
return (letter - 0x20);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
2
applications/external/subbrute
vendored
2
applications/external/subbrute
vendored
Submodule applications/external/subbrute updated: a2d198782d...32290f6b5f
2
applications/external/totp/application.fam
vendored
2
applications/external/totp/application.fam
vendored
@@ -15,7 +15,7 @@ App(
|
|||||||
],
|
],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=20,
|
order=20,
|
||||||
fap_version="2.3",
|
fap_version="3.20",
|
||||||
fap_author="Alexander Kopachov (@akopachov)",
|
fap_author="Alexander Kopachov (@akopachov)",
|
||||||
fap_description="Software-based TOTP authenticator for Flipper Zero device",
|
fap_description="Software-based TOTP authenticator for Flipper Zero device",
|
||||||
fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",
|
fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",
|
||||||
|
|||||||
10
applications/external/totp/cli/cli.c
vendored
10
applications/external/totp/cli/cli.c
vendored
@@ -16,6 +16,10 @@
|
|||||||
#include "commands/automation/automation.h"
|
#include "commands/automation/automation.h"
|
||||||
#include "commands/details/details.h"
|
#include "commands/details/details.h"
|
||||||
|
|
||||||
|
struct TotpCliContext {
|
||||||
|
PluginState* plugin_state;
|
||||||
|
};
|
||||||
|
|
||||||
static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
|
static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
|
||||||
TOTP_CLI_PRINTF_ERROR(
|
TOTP_CLI_PRINTF_ERROR(
|
||||||
"Command \"%s\" is unknown. Use \"" TOTP_CLI_COMMAND_HELP
|
"Command \"%s\" is unknown. Use \"" TOTP_CLI_COMMAND_HELP
|
||||||
@@ -63,7 +67,7 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
|
|||||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
|
||||||
totp_cli_command_automation_handle(plugin_state, args, cli);
|
totp_cli_command_automation_handle(plugin_state, args, cli);
|
||||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
|
||||||
totp_cli_command_reset_handle(plugin_state, cli, cli_context->event_queue);
|
totp_cli_command_reset_handle(plugin_state, cli);
|
||||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
|
||||||
totp_cli_command_update_handle(plugin_state, args, cli);
|
totp_cli_command_update_handle(plugin_state, args, cli);
|
||||||
} else if(
|
} else if(
|
||||||
@@ -77,13 +81,11 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
|
|||||||
furi_string_free(cmd);
|
furi_string_free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
TotpCliContext*
|
TotpCliContext* totp_cli_register_command_handler(PluginState* plugin_state) {
|
||||||
totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue) {
|
|
||||||
Cli* cli = furi_record_open(RECORD_CLI);
|
Cli* cli = furi_record_open(RECORD_CLI);
|
||||||
TotpCliContext* context = malloc(sizeof(TotpCliContext));
|
TotpCliContext* context = malloc(sizeof(TotpCliContext));
|
||||||
furi_check(context != NULL);
|
furi_check(context != NULL);
|
||||||
context->plugin_state = plugin_state;
|
context->plugin_state = plugin_state;
|
||||||
context->event_queue = event_queue;
|
|
||||||
cli_add_command(
|
cli_add_command(
|
||||||
cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context);
|
cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context);
|
||||||
furi_record_close(RECORD_CLI);
|
furi_record_close(RECORD_CLI);
|
||||||
|
|||||||
18
applications/external/totp/cli/cli.h
vendored
18
applications/external/totp/cli/cli.h
vendored
@@ -3,11 +3,17 @@
|
|||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include "../types/plugin_state.h"
|
#include "../types/plugin_state.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct TotpCliContext TotpCliContext;
|
||||||
PluginState* plugin_state;
|
|
||||||
FuriMessageQueue* event_queue;
|
|
||||||
} TotpCliContext;
|
|
||||||
|
|
||||||
TotpCliContext*
|
/**
|
||||||
totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue);
|
* @brief Registers TOTP CLI handler
|
||||||
|
* @param plugin_state application state
|
||||||
|
* @return TOTP CLI context
|
||||||
|
*/
|
||||||
|
TotpCliContext* totp_cli_register_command_handler(PluginState* plugin_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregisters TOTP CLI handler
|
||||||
|
* @param context application state
|
||||||
|
*/
|
||||||
void totp_cli_unregister_command_handler(TotpCliContext* context);
|
void totp_cli_unregister_command_handler(TotpCliContext* context);
|
||||||
8
applications/external/totp/cli/cli_helpers.h
vendored
8
applications/external/totp/cli/cli_helpers.h
vendored
@@ -35,10 +35,12 @@ extern const char* TOTP_CLI_COLOR_INFO;
|
|||||||
|
|
||||||
#define TOTP_CLI_LOCK_UI(plugin_state) \
|
#define TOTP_CLI_LOCK_UI(plugin_state) \
|
||||||
Scene __previous_scene = plugin_state->current_scene; \
|
Scene __previous_scene = plugin_state->current_scene; \
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneStandby)
|
totp_scene_director_activate_scene(plugin_state, TotpSceneStandby); \
|
||||||
|
totp_scene_director_force_redraw(plugin_state)
|
||||||
|
|
||||||
#define TOTP_CLI_UNLOCK_UI(plugin_state) \
|
#define TOTP_CLI_UNLOCK_UI(plugin_state) \
|
||||||
totp_scene_director_activate_scene(plugin_state, __previous_scene)
|
totp_scene_director_activate_scene(plugin_state, __previous_scene); \
|
||||||
|
totp_scene_director_force_redraw(plugin_state)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether user is authenticated and entered correct PIN.
|
* @brief Checks whether user is authenticated and entered correct PIN.
|
||||||
@@ -109,6 +111,6 @@ void totp_cli_print_error_updating_config_file();
|
|||||||
void totp_cli_print_error_loading_token_info();
|
void totp_cli_print_error_loading_token_info();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prints message to let user knwo that command is processing now
|
* @brief Prints message to let user know that command is processing now
|
||||||
*/
|
*/
|
||||||
void totp_cli_print_processing();
|
void totp_cli_print_processing();
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
struct TotpAddContext {
|
struct TotpAddContext {
|
||||||
FuriString* args;
|
FuriString* args;
|
||||||
Cli* cli;
|
Cli* cli;
|
||||||
uint8_t* iv;
|
const CryptoSettings* crypto_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TotpIteratorUpdateTokenResultsEx {
|
enum TotpIteratorUpdateTokenResultsEx {
|
||||||
@@ -54,7 +54,7 @@ static TotpIteratorUpdateTokenResult
|
|||||||
|
|
||||||
// Reading token secret
|
// Reading token secret
|
||||||
furi_string_reset(temp_str);
|
furi_string_reset(temp_str);
|
||||||
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
|
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]:\r\n");
|
||||||
if(!totp_cli_read_line(context_t->cli, temp_str, mask_user_input)) {
|
if(!totp_cli_read_line(context_t->cli, temp_str, mask_user_input)) {
|
||||||
totp_cli_delete_last_line();
|
totp_cli_delete_last_line();
|
||||||
furi_string_secure_free(temp_str);
|
furi_string_secure_free(temp_str);
|
||||||
@@ -68,7 +68,7 @@ static TotpIteratorUpdateTokenResult
|
|||||||
furi_string_get_cstr(temp_str),
|
furi_string_get_cstr(temp_str),
|
||||||
furi_string_size(temp_str),
|
furi_string_size(temp_str),
|
||||||
token_secret_encoding,
|
token_secret_encoding,
|
||||||
context_t->iv);
|
context_t->crypto_settings);
|
||||||
|
|
||||||
furi_string_secure_free(temp_str);
|
furi_string_secure_free(temp_str);
|
||||||
|
|
||||||
@@ -166,7 +166,8 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
|
|||||||
|
|
||||||
TOTP_CLI_LOCK_UI(plugin_state);
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
|
|
||||||
struct TotpAddContext add_context = {.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
struct TotpAddContext add_context = {
|
||||||
|
.args = args, .cli = cli, .crypto_settings = &plugin_state->crypto_settings};
|
||||||
TotpIteratorUpdateTokenResult add_result =
|
TotpIteratorUpdateTokenResult add_result =
|
||||||
totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
|
totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,23 @@
|
|||||||
#define TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD "automation"
|
#define TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD "automation"
|
||||||
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "none"
|
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "none"
|
||||||
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "usb"
|
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "usb"
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt"
|
#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt"
|
||||||
#endif
|
#endif
|
||||||
|
#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY "QWERTY"
|
||||||
|
#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY "AZERTY"
|
||||||
|
#define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX "-k"
|
||||||
|
#define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT "layout"
|
||||||
|
|
||||||
void totp_cli_command_automation_docopt_commands() {
|
void totp_cli_command_automation_docopt_commands() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation method\r\n");
|
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation settings\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_cli_command_automation_docopt_usage() {
|
void totp_cli_command_automation_docopt_usage() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL(
|
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL(DOCOPT_OPTION(
|
||||||
DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n");
|
TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX,
|
||||||
|
DOCOPT_ARGUMENT(
|
||||||
|
TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT))) " " DOCOPT_OPTIONAL(DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_cli_command_automation_docopt_arguments() {
|
void totp_cli_command_automation_docopt_arguments() {
|
||||||
@@ -25,24 +31,33 @@ void totp_cli_command_automation_docopt_arguments() {
|
|||||||
" " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD
|
" " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD
|
||||||
" Automation method to be set. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE
|
" Automation method to be set. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE
|
||||||
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB
|
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT
|
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT
|
||||||
#endif
|
#endif
|
||||||
"\r\n");
|
"\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void totp_cli_command_automation_print_method(AutomationMethod method, const char* color) {
|
void totp_cli_command_automation_docopt_options() {
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
|
||||||
|
TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX,
|
||||||
|
DOCOPT_ARGUMENT(
|
||||||
|
TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT)) " Automation keyboard layout. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY
|
||||||
|
", " TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY
|
||||||
|
"\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_method(AutomationMethod method, const char* color) {
|
||||||
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
bool has_previous_method = false;
|
bool has_previous_method = false;
|
||||||
#endif
|
#endif
|
||||||
if(method & AutomationMethodBadUsb) {
|
if(method & AutomationMethodBadUsb) {
|
||||||
TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "\"");
|
TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "\"");
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
has_previous_method = true;
|
has_previous_method = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(method & AutomationMethodBadBt) {
|
if(method & AutomationMethodBadBt) {
|
||||||
if(has_previous_method) {
|
if(has_previous_method) {
|
||||||
TOTP_CLI_PRINTF_COLORFUL(color, " and ");
|
TOTP_CLI_PRINTF_COLORFUL(color, " and ");
|
||||||
@@ -57,6 +72,37 @@ static void totp_cli_command_automation_print_method(AutomationMethod method, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
furi_crash("Unknown automation keyboard layout");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOTP_CLI_PRINTF_COLORFUL(color, "%s", layoutToPrint);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||||
return;
|
return;
|
||||||
@@ -65,6 +111,7 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
FuriString* temp_str = furi_string_alloc();
|
FuriString* temp_str = furi_string_alloc();
|
||||||
bool new_method_provided = false;
|
bool new_method_provided = false;
|
||||||
AutomationMethod new_method = AutomationMethodNone;
|
AutomationMethod new_method = AutomationMethodNone;
|
||||||
|
AutomationKeyboardLayout new_kb_layout = plugin_state->automation_kb_layout;
|
||||||
bool args_valid = true;
|
bool args_valid = true;
|
||||||
while(args_read_string_and_trim(args, temp_str)) {
|
while(args_read_string_and_trim(args, temp_str)) {
|
||||||
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) {
|
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) {
|
||||||
@@ -74,13 +121,19 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
new_method_provided = true;
|
new_method_provided = true;
|
||||||
new_method |= AutomationMethodBadUsb;
|
new_method |= AutomationMethodBadUsb;
|
||||||
}
|
}
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT) == 0) {
|
else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT) == 0) {
|
||||||
new_method_provided = true;
|
new_method_provided = true;
|
||||||
new_method |= AutomationMethodBadBt;
|
new_method |= AutomationMethodBadBt;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
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)) {
|
||||||
|
args_valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
args_valid = false;
|
args_valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -96,15 +149,19 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
TOTP_CLI_LOCK_UI(plugin_state);
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
|
|
||||||
plugin_state->automation_method = new_method;
|
plugin_state->automation_method = new_method;
|
||||||
|
plugin_state->automation_kb_layout = new_kb_layout;
|
||||||
if(totp_config_file_update_automation_method(plugin_state)) {
|
if(totp_config_file_update_automation_method(plugin_state)) {
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
|
TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
|
||||||
totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
||||||
|
TOTP_CLI_PRINTF_SUCCESS(" (");
|
||||||
|
print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_SUCCESS);
|
||||||
|
TOTP_CLI_PRINTF_SUCCESS(")");
|
||||||
cli_nl();
|
cli_nl();
|
||||||
} else {
|
} else {
|
||||||
totp_cli_print_error_updating_config_file();
|
totp_cli_print_error_updating_config_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(!(new_method & AutomationMethodBadBt) &&
|
if(!(new_method & AutomationMethodBadBt) &&
|
||||||
plugin_state->bt_type_code_worker_context != NULL) {
|
plugin_state->bt_type_code_worker_context != NULL) {
|
||||||
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
||||||
@@ -115,8 +172,10 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("Current automation method is ");
|
TOTP_CLI_PRINTF_INFO("Current automation method is ");
|
||||||
totp_cli_command_automation_print_method(
|
print_method(plugin_state->automation_method, TOTP_CLI_COLOR_INFO);
|
||||||
plugin_state->automation_method, TOTP_CLI_COLOR_INFO);
|
TOTP_CLI_PRINTF_INFO(" (");
|
||||||
|
print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_INFO);
|
||||||
|
TOTP_CLI_PRINTF_INFO(")");
|
||||||
cli_nl();
|
cli_nl();
|
||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
void totp_cli_command_automation_docopt_commands();
|
void totp_cli_command_automation_docopt_commands();
|
||||||
void totp_cli_command_automation_docopt_usage();
|
void totp_cli_command_automation_docopt_usage();
|
||||||
void totp_cli_command_automation_docopt_arguments();
|
void totp_cli_command_automation_docopt_arguments();
|
||||||
|
void totp_cli_command_automation_docopt_options();
|
||||||
@@ -64,4 +64,6 @@ void totp_cli_command_help_handle() {
|
|||||||
totp_cli_command_add_docopt_options();
|
totp_cli_command_add_docopt_options();
|
||||||
totp_cli_command_update_docopt_options();
|
totp_cli_command_update_docopt_options();
|
||||||
totp_cli_command_delete_docopt_options();
|
totp_cli_command_delete_docopt_options();
|
||||||
|
totp_cli_command_pin_docopt_options();
|
||||||
|
totp_cli_command_automation_docopt_options();
|
||||||
}
|
}
|
||||||
@@ -7,19 +7,35 @@
|
|||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
#include <memset_s.h>
|
#include <memset_s.h>
|
||||||
#include "../../../services/crypto/crypto.h"
|
#include "../../../services/crypto/crypto_facade.h"
|
||||||
#include "../../../ui/scene_director.h"
|
#include "../../../ui/scene_director.h"
|
||||||
|
|
||||||
#define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set"
|
#define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set"
|
||||||
#define TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE "remove"
|
#define TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE "remove"
|
||||||
|
#define TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX "-c"
|
||||||
|
#define TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT "slot"
|
||||||
|
|
||||||
void totp_cli_command_pin_docopt_commands() {
|
void totp_cli_command_pin_docopt_commands() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_PIN " Set\\change\\remove PIN\r\n");
|
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_PIN " Set\\change\\remove PIN\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_cli_command_pin_docopt_usage() {
|
void totp_cli_command_pin_docopt_usage() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_PIN " " DOCOPT_REQUIRED(
|
TOTP_CLI_PRINTF(
|
||||||
TOTP_CLI_COMMAND_PIN_COMMAND_SET " | " TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) "\r\n");
|
" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_PIN
|
||||||
|
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_PIN_COMMAND_SET " | " TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) " " DOCOPT_OPTIONAL(
|
||||||
|
DOCOPT_OPTION(
|
||||||
|
TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX,
|
||||||
|
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT))) "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void totp_cli_command_pin_docopt_options() {
|
||||||
|
TOTP_CLI_PRINTF(
|
||||||
|
" " DOCOPT_OPTION(
|
||||||
|
TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX,
|
||||||
|
DOCOPT_ARGUMENT(
|
||||||
|
TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT)) " New crypto key slot. Must be between %d and %d\r\n",
|
||||||
|
ACCEPTABLE_CRYPTO_KEY_SLOT_START,
|
||||||
|
ACCEPTABLE_CRYPTO_KEY_SLOT_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t totp_cli_key_to_pin_code(uint8_t key) {
|
static inline uint8_t totp_cli_key_to_pin_code(uint8_t key) {
|
||||||
@@ -89,35 +105,49 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
|||||||
|
|
||||||
bool do_change = false;
|
bool do_change = false;
|
||||||
bool do_remove = false;
|
bool do_remove = false;
|
||||||
UNUSED(do_remove);
|
uint8_t crypto_key_slot = plugin_state->crypto_settings.crypto_key_slot;
|
||||||
if(args_read_string_and_trim(args, temp_str)) {
|
|
||||||
|
bool arguments_parsed = true;
|
||||||
|
while(args_read_string_and_trim(args, temp_str)) {
|
||||||
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_SET) == 0) {
|
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_SET) == 0) {
|
||||||
do_change = true;
|
do_change = true;
|
||||||
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
|
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
|
||||||
do_remove = true;
|
do_remove = true;
|
||||||
} else {
|
} else if(
|
||||||
totp_cli_print_invalid_arguments();
|
furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX) ==
|
||||||
|
0) {
|
||||||
|
if(!args_read_uint8_and_trim(args, &crypto_key_slot) ||
|
||||||
|
!totp_crypto_check_key_slot(crypto_key_slot)) {
|
||||||
|
TOTP_CLI_PRINTF_ERROR("Slot \"%" PRIu8 "\" can not be used\r\n", crypto_key_slot);
|
||||||
|
arguments_parsed = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
totp_cli_print_invalid_arguments();
|
totp_cli_print_invalid_arguments();
|
||||||
|
arguments_parsed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) {
|
if(!(do_change || do_remove) || (do_change && do_remove)) {
|
||||||
|
totp_cli_print_invalid_arguments();
|
||||||
|
arguments_parsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(arguments_parsed && totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||||
TOTP_CLI_LOCK_UI(plugin_state);
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
do {
|
do {
|
||||||
uint8_t old_iv[TOTP_IV_SIZE];
|
uint8_t new_pin[CRYPTO_IV_LENGTH];
|
||||||
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
memset(&new_pin[0], 0, CRYPTO_IV_LENGTH);
|
||||||
uint8_t new_pin[TOTP_IV_SIZE];
|
|
||||||
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
|
||||||
uint8_t new_pin_length = 0;
|
uint8_t new_pin_length = 0;
|
||||||
if(do_change) {
|
if(do_change) {
|
||||||
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) {
|
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) {
|
||||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(do_remove) {
|
} else if(do_remove) {
|
||||||
new_pin_length = 0;
|
new_pin_length = 0;
|
||||||
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
memset(&new_pin[0], 0, CRYPTO_IV_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* backup_path = totp_config_file_backup(plugin_state);
|
char* backup_path = totp_config_file_backup(plugin_state);
|
||||||
@@ -127,7 +157,7 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
|||||||
"Once you make sure everything is fine and works as expected, please delete this backup file\r\n");
|
"Once you make sure everything is fine and works as expected, please delete this backup file\r\n");
|
||||||
free(backup_path);
|
free(backup_path);
|
||||||
} else {
|
} else {
|
||||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH);
|
||||||
TOTP_CLI_PRINTF_ERROR(
|
TOTP_CLI_PRINTF_ERROR(
|
||||||
"An error has occurred during taking backup of config file\r\n");
|
"An error has occurred during taking backup of config file\r\n");
|
||||||
break;
|
break;
|
||||||
@@ -135,10 +165,10 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
|||||||
|
|
||||||
TOTP_CLI_PRINTF("Encrypting...\r\n");
|
TOTP_CLI_PRINTF("Encrypting...\r\n");
|
||||||
|
|
||||||
bool update_result =
|
bool update_result = totp_config_file_update_encryption(
|
||||||
totp_config_file_update_encryption(plugin_state, new_pin, new_pin_length);
|
plugin_state, crypto_key_slot, new_pin, new_pin_length);
|
||||||
|
|
||||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH);
|
||||||
|
|
||||||
totp_cli_delete_last_line();
|
totp_cli_delete_last_line();
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,4 @@
|
|||||||
void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
|
void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
|
||||||
void totp_cli_command_pin_docopt_commands();
|
void totp_cli_command_pin_docopt_commands();
|
||||||
void totp_cli_command_pin_docopt_usage();
|
void totp_cli_command_pin_docopt_usage();
|
||||||
|
void totp_cli_command_pin_docopt_options();
|
||||||
@@ -17,10 +17,7 @@ void totp_cli_command_reset_docopt_usage() {
|
|||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_RESET "\r\n");
|
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_RESET "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_cli_command_reset_handle(
|
void totp_cli_command_reset_handle(PluginState* plugin_state, Cli* cli) {
|
||||||
PluginState* plugin_state,
|
|
||||||
Cli* cli,
|
|
||||||
FuriMessageQueue* event_queue) {
|
|
||||||
TOTP_CLI_LOCK_UI(plugin_state);
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
TOTP_CLI_PRINTF_WARNING(
|
TOTP_CLI_PRINTF_WARNING(
|
||||||
"As a result of reset all the settings and tokens will be permanently lost.\r\n");
|
"As a result of reset all the settings and tokens will be permanently lost.\r\n");
|
||||||
@@ -35,7 +32,7 @@ void totp_cli_command_reset_handle(
|
|||||||
totp_config_file_reset(plugin_state);
|
totp_config_file_reset(plugin_state);
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Application has been successfully reset to default.\r\n");
|
TOTP_CLI_PRINTF_SUCCESS("Application has been successfully reset to default.\r\n");
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Now application will be closed to apply all the changes.\r\n");
|
TOTP_CLI_PRINTF_SUCCESS("Now application will be closed to apply all the changes.\r\n");
|
||||||
totp_cli_force_close_app(event_queue);
|
totp_cli_force_close_app(plugin_state->event_queue);
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
|
TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
|
||||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
#define TOTP_CLI_COMMAND_RESET "reset"
|
#define TOTP_CLI_COMMAND_RESET "reset"
|
||||||
|
|
||||||
void totp_cli_command_reset_handle(
|
void totp_cli_command_reset_handle(PluginState* plugin_state, Cli* cli);
|
||||||
PluginState* plugin_state,
|
|
||||||
Cli* cli,
|
|
||||||
FuriMessageQueue* event_queue);
|
|
||||||
void totp_cli_command_reset_docopt_commands();
|
void totp_cli_command_reset_docopt_commands();
|
||||||
void totp_cli_command_reset_docopt_usage();
|
void totp_cli_command_reset_docopt_usage();
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
struct TotpUpdateContext {
|
struct TotpUpdateContext {
|
||||||
FuriString* args;
|
FuriString* args;
|
||||||
Cli* cli;
|
Cli* cli;
|
||||||
uint8_t* iv;
|
const CryptoSettings* crypto_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TotpIteratorUpdateTokenResultsEx {
|
enum TotpIteratorUpdateTokenResultsEx {
|
||||||
@@ -83,7 +83,7 @@ static TotpIteratorUpdateTokenResult
|
|||||||
if(update_token_secret) {
|
if(update_token_secret) {
|
||||||
// Reading token secret
|
// Reading token secret
|
||||||
furi_string_reset(temp_str);
|
furi_string_reset(temp_str);
|
||||||
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
|
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]:\r\n");
|
||||||
bool token_secret_read = totp_cli_read_line(context_t->cli, temp_str, mask_user_input);
|
bool token_secret_read = totp_cli_read_line(context_t->cli, temp_str, mask_user_input);
|
||||||
totp_cli_delete_last_line();
|
totp_cli_delete_last_line();
|
||||||
if(!token_secret_read) {
|
if(!token_secret_read) {
|
||||||
@@ -96,7 +96,7 @@ static TotpIteratorUpdateTokenResult
|
|||||||
furi_string_get_cstr(temp_str),
|
furi_string_get_cstr(temp_str),
|
||||||
furi_string_size(temp_str),
|
furi_string_size(temp_str),
|
||||||
token_secret_encoding,
|
token_secret_encoding,
|
||||||
context_t->iv)) {
|
context_t->crypto_settings)) {
|
||||||
furi_string_secure_free(temp_str);
|
furi_string_secure_free(temp_str);
|
||||||
return TotpIteratorUpdateTokenResultInvalidSecret;
|
return TotpIteratorUpdateTokenResultInvalidSecret;
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,7 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args,
|
|||||||
totp_token_info_iterator_go_to(iterator_context, token_number - 1);
|
totp_token_info_iterator_go_to(iterator_context, token_number - 1);
|
||||||
|
|
||||||
struct TotpUpdateContext update_context = {
|
struct TotpUpdateContext update_context = {
|
||||||
.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
.args = args, .cli = cli, .crypto_settings = &plugin_state->crypto_settings};
|
||||||
TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
|
TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
|
||||||
iterator_context, &update_token_handler, &update_context);
|
iterator_context, &update_token_handler, &update_context);
|
||||||
|
|
||||||
|
|||||||
@@ -18,32 +18,87 @@
|
|||||||
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX "-e"
|
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX "-e"
|
||||||
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding"
|
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints information about unknown argument
|
||||||
|
* @param arg
|
||||||
|
*/
|
||||||
void totp_cli_printf_unknown_argument(const FuriString* arg);
|
void totp_cli_printf_unknown_argument(const FuriString* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints information about missed required argument
|
||||||
|
* @param arg
|
||||||
|
*/
|
||||||
void totp_cli_printf_missed_argument_value(char* arg);
|
void totp_cli_printf_missed_argument_value(char* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read token hashing algo
|
||||||
|
* @param token_info token info to set parsed algo to if successfully read and parsed
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param args rest of arguments
|
||||||
|
* @param[out] parsed will be set to \c true if token hashing algo sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @return \c true if \c arg represents token hashing algo argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed);
|
bool totp_cli_try_read_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read token digits count
|
||||||
|
* @param token_info token info to set parsed digits count to if successfully read and parsed
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param args rest of arguments
|
||||||
|
* @param[out] parsed will be set to \c true if token digits count sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @return \c true if \c arg represents token digits count argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_digits(
|
bool totp_cli_try_read_digits(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
const FuriString* arg,
|
const FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read token duration
|
||||||
|
* @param token_info token info to set parsed duration to if successfully read and parsed
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param args rest of arguments
|
||||||
|
* @param[out] parsed will be set to \c true if token duration sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @return \c true if \c arg represents token duration argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_duration(
|
bool totp_cli_try_read_duration(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
const FuriString* arg,
|
const FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read token automation features
|
||||||
|
* @param token_info token info to set parsed automation features to if successfully read and parsed
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param args rest of arguments
|
||||||
|
* @param[out] parsed will be set to \c true if token automation features sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @return \c true if \c arg represents token automation features argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_automation_features(
|
bool totp_cli_try_read_automation_features(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
FuriString* arg,
|
FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read unsecure flag
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param[out] parsed will be set to \c true if unsecure flag sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @param[out] unsecure_flag will be set to parsed unsecure flag state if read and parsed successfully
|
||||||
|
* @return \c true if \c arg represents unsecure flag argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag);
|
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read plain token secret encoding
|
||||||
|
* @param arg argument to parse
|
||||||
|
* @param args rest of arguments
|
||||||
|
* @param[out] parsed will be set to \c true if plain token secret encoding sucecssfully read and parsed; \c false otherwise
|
||||||
|
* @param[out] secret_encoding will be set to parsed plain token secret encoding if read and parsed successfully
|
||||||
|
* @return \c true if \c arg represents plain token secret encoding argument; \c false otherwise
|
||||||
|
*/
|
||||||
bool totp_cli_try_read_plain_token_secret_encoding(
|
bool totp_cli_try_read_plain_token_secret_encoding(
|
||||||
FuriString* arg,
|
FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
|
|||||||
10
applications/external/totp/features_config.h
vendored
10
applications/external/totp/features_config.h
vendored
@@ -4,13 +4,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Include Bluetooth token input automation
|
// Include Bluetooth token input automation
|
||||||
#ifndef TOTP_NO_BADBT_TYPE
|
#ifndef TOTP_NO_BADBT_AUTOMATION
|
||||||
#define TOTP_BADBT_TYPE_ENABLED
|
#define TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
#endif
|
|
||||||
|
|
||||||
// Include token input automation icons on the main screen
|
|
||||||
#ifndef TOTP_NO_AUTOMATION_ICONS
|
|
||||||
#define TOTP_AUTOMATION_ICONS_ENABLED
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// List of compatible firmwares
|
// List of compatible firmwares
|
||||||
@@ -19,6 +14,7 @@
|
|||||||
#define TOTP_FIRMWARE_XTREME_UL (3)
|
#define TOTP_FIRMWARE_XTREME_UL (3)
|
||||||
// End of list
|
// End of list
|
||||||
|
|
||||||
|
// Target firmware
|
||||||
#ifndef TOTP_TARGET_FIRMWARE
|
#ifndef TOTP_TARGET_FIRMWARE
|
||||||
#define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME_UL
|
#define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME_UL
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 147 B |
236
applications/external/totp/services/config/config.c
vendored
236
applications/external/totp/services/config/config.c
vendored
@@ -9,7 +9,8 @@
|
|||||||
#include "../../types/common.h"
|
#include "../../types/common.h"
|
||||||
#include "../../types/token_info.h"
|
#include "../../types/token_info.h"
|
||||||
#include "../../features_config.h"
|
#include "../../features_config.h"
|
||||||
#include "../crypto/crypto.h"
|
#include "../crypto/crypto_facade.h"
|
||||||
|
#include "../crypto/constants.h"
|
||||||
#include "migrations/common_migration.h"
|
#include "migrations/common_migration.h"
|
||||||
|
|
||||||
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
|
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
|
||||||
@@ -110,7 +111,16 @@ static char* totp_config_file_backup_i(Storage* storage) {
|
|||||||
static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||||
|
|
||||||
if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) {
|
bool conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK;
|
||||||
|
if(!conf_file_exists) {
|
||||||
|
FURI_LOG_I(LOGGING_TAG, "Application catalog needs to be migrated");
|
||||||
|
FS_Error migration_result =
|
||||||
|
storage_common_migrate(storage, EXT_PATH("authenticator"), CONFIG_FILE_DIRECTORY_PATH);
|
||||||
|
FURI_LOG_I(LOGGING_TAG, "Migrated catalog. Result code: %d", (int)migration_result);
|
||||||
|
conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conf_file_exists) {
|
||||||
FURI_LOG_D(LOGGING_TAG, "Config file %s found", CONFIG_FILE_PATH);
|
FURI_LOG_D(LOGGING_TAG, "Config file %s found", CONFIG_FILE_PATH);
|
||||||
if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) {
|
if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) {
|
||||||
FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH);
|
FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH);
|
||||||
@@ -119,16 +129,6 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH);
|
FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH);
|
||||||
if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
|
|
||||||
FURI_LOG_D(
|
|
||||||
LOGGING_TAG,
|
|
||||||
"Directory %s doesn't exist. Will create new.",
|
|
||||||
CONFIG_FILE_DIRECTORY_PATH);
|
|
||||||
if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
|
|
||||||
FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) {
|
if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) {
|
||||||
totp_close_config_file(fff_data_file);
|
totp_close_config_file(fff_data_file);
|
||||||
@@ -139,6 +139,13 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
|||||||
flipper_format_write_header_cstr(
|
flipper_format_write_header_cstr(
|
||||||
fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
|
fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
|
||||||
|
|
||||||
|
uint32_t tmp_uint32 = CRYPTO_LATEST_VERSION;
|
||||||
|
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1);
|
||||||
|
|
||||||
|
tmp_uint32 = DEFAULT_CRYPTO_KEY_SLOT;
|
||||||
|
flipper_format_write_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1);
|
||||||
|
|
||||||
flipper_format_write_comment_cstr(
|
flipper_format_write_comment_cstr(
|
||||||
fff_data_file,
|
fff_data_file,
|
||||||
"Config file format specification can be found here: https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md");
|
"Config file format specification can be found here: https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md");
|
||||||
@@ -146,7 +153,7 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
|||||||
float tmp_tz = 0;
|
float tmp_tz = 0;
|
||||||
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
|
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
|
||||||
|
|
||||||
uint32_t tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
||||||
flipper_format_write_uint32(
|
flipper_format_write_uint32(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
|
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
|
||||||
|
|
||||||
@@ -154,7 +161,11 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
|||||||
flipper_format_write_uint32(
|
flipper_format_write_uint32(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1);
|
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1);
|
||||||
|
|
||||||
tmp_uint32 = 0;
|
tmp_uint32 = AutomationKeyboardLayoutQWERTY;
|
||||||
|
flipper_format_write_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1);
|
||||||
|
|
||||||
|
tmp_uint32 = 0; //-V1048
|
||||||
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1);
|
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1);
|
||||||
|
|
||||||
if(!flipper_format_rewind(fff_data_file)) {
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
@@ -233,6 +244,12 @@ bool totp_config_file_update_automation_method(const PluginState* plugin_state)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp_uint32 = plugin_state->automation_kb_layout;
|
||||||
|
if(!flipper_format_insert_or_update_uint32(
|
||||||
|
file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
update_result = true;
|
update_result = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -265,6 +282,12 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp_uint32 = plugin_state->automation_kb_layout;
|
||||||
|
if(!flipper_format_insert_or_update_uint32(
|
||||||
|
file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
update_result = true;
|
update_result = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -344,8 +367,38 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t tmp_uint32;
|
||||||
|
|
||||||
|
if(!flipper_format_read_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) {
|
||||||
|
FURI_LOG_E(LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_VERSION "property");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_state->crypto_settings.crypto_version = tmp_uint32;
|
||||||
|
|
||||||
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!flipper_format_read_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) {
|
||||||
|
FURI_LOG_E(
|
||||||
|
LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "property");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_state->crypto_settings.crypto_key_slot = tmp_uint32;
|
||||||
|
|
||||||
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(!flipper_format_read_hex(
|
if(!flipper_format_read_hex(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
|
fff_data_file,
|
||||||
|
TOTP_CONFIG_KEY_BASE_IV,
|
||||||
|
&plugin_state->crypto_settings.base_iv[0],
|
||||||
|
CRYPTO_IV_LENGTH)) {
|
||||||
FURI_LOG_D(LOGGING_TAG, "Missing base IV");
|
FURI_LOG_D(LOGGING_TAG, "Missing base IV");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,22 +410,23 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
if(flipper_format_get_value_count(
|
if(flipper_format_get_value_count(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
|
||||||
crypto_size > 0) {
|
crypto_size > 0) {
|
||||||
plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
|
plugin_state->crypto_settings.crypto_verify_data =
|
||||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
malloc(sizeof(uint8_t) * crypto_size);
|
||||||
plugin_state->crypto_verify_data_length = crypto_size;
|
furi_check(plugin_state->crypto_settings.crypto_verify_data != NULL);
|
||||||
|
plugin_state->crypto_settings.crypto_verify_data_length = crypto_size;
|
||||||
if(!flipper_format_read_hex(
|
if(!flipper_format_read_hex(
|
||||||
fff_data_file,
|
fff_data_file,
|
||||||
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
||||||
plugin_state->crypto_verify_data,
|
plugin_state->crypto_settings.crypto_verify_data,
|
||||||
crypto_size)) {
|
crypto_size)) {
|
||||||
FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
|
FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
|
||||||
free(plugin_state->crypto_verify_data);
|
free(plugin_state->crypto_settings.crypto_verify_data);
|
||||||
plugin_state->crypto_verify_data = NULL;
|
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||||
plugin_state->crypto_verify_data_length = 0;
|
plugin_state->crypto_settings.crypto_verify_data_length = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
plugin_state->crypto_verify_data = NULL;
|
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||||
plugin_state->crypto_verify_data_length = 0;
|
plugin_state->crypto_settings.crypto_verify_data_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flipper_format_rewind(fff_data_file)) {
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
@@ -390,13 +444,17 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!flipper_format_read_bool(
|
if(!flipper_format_read_bool(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
|
fff_data_file,
|
||||||
plugin_state->pin_set = true;
|
TOTP_CONFIG_KEY_PINSET,
|
||||||
|
&plugin_state->crypto_settings.pin_required,
|
||||||
|
1)) {
|
||||||
|
plugin_state->crypto_settings.pin_required = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
flipper_format_rewind(fff_data_file);
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t tmp_uint32;
|
|
||||||
if(!flipper_format_read_uint32(
|
if(!flipper_format_read_uint32(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
|
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
|
||||||
tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
||||||
@@ -404,7 +462,9 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
|
|
||||||
plugin_state->notification_method = tmp_uint32;
|
plugin_state->notification_method = tmp_uint32;
|
||||||
|
|
||||||
flipper_format_rewind(fff_data_file);
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(!flipper_format_read_uint32(
|
if(!flipper_format_read_uint32(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) {
|
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) {
|
||||||
@@ -413,6 +473,21 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
|
|
||||||
plugin_state->automation_method = tmp_uint32;
|
plugin_state->automation_method = tmp_uint32;
|
||||||
|
|
||||||
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!flipper_format_read_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||||
|
tmp_uint32 = AutomationKeyboardLayoutQWERTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_state->automation_kb_layout = tmp_uint32;
|
||||||
|
|
||||||
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
|
if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
|
||||||
tmp_uint32 = 0;
|
tmp_uint32 = 0;
|
||||||
}
|
}
|
||||||
@@ -425,7 +500,9 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
|||||||
plugin_state->config_file_context->config_file = fff_data_file;
|
plugin_state->config_file_context->config_file = fff_data_file;
|
||||||
plugin_state->config_file_context->token_info_iterator_context =
|
plugin_state->config_file_context->token_info_iterator_context =
|
||||||
totp_token_info_iterator_alloc(
|
totp_token_info_iterator_alloc(
|
||||||
storage, plugin_state->config_file_context->config_file, plugin_state->iv);
|
storage,
|
||||||
|
plugin_state->config_file_context->config_file,
|
||||||
|
&plugin_state->crypto_settings);
|
||||||
result = true;
|
result = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -438,21 +515,39 @@ bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state)
|
|||||||
flipper_format_rewind(config_file);
|
flipper_format_rewind(config_file);
|
||||||
bool update_result = false;
|
bool update_result = false;
|
||||||
do {
|
do {
|
||||||
|
uint32_t tmp_uint32 = plugin_state->crypto_settings.crypto_version;
|
||||||
|
if(!flipper_format_insert_or_update_uint32(
|
||||||
|
config_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_uint32 = plugin_state->crypto_settings.crypto_key_slot;
|
||||||
|
if(!flipper_format_insert_or_update_uint32(
|
||||||
|
config_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(!flipper_format_insert_or_update_hex(
|
if(!flipper_format_insert_or_update_hex(
|
||||||
config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE)) {
|
config_file,
|
||||||
|
TOTP_CONFIG_KEY_BASE_IV,
|
||||||
|
plugin_state->crypto_settings.base_iv,
|
||||||
|
CRYPTO_IV_LENGTH)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flipper_format_insert_or_update_hex(
|
if(!flipper_format_insert_or_update_hex(
|
||||||
config_file,
|
config_file,
|
||||||
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
||||||
plugin_state->crypto_verify_data,
|
plugin_state->crypto_settings.crypto_verify_data,
|
||||||
plugin_state->crypto_verify_data_length)) {
|
plugin_state->crypto_settings.crypto_verify_data_length)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flipper_format_insert_or_update_bool(
|
if(!flipper_format_insert_or_update_bool(
|
||||||
config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
|
config_file,
|
||||||
|
TOTP_CONFIG_KEY_PINSET,
|
||||||
|
&plugin_state->crypto_settings.pin_required,
|
||||||
|
1)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +575,7 @@ void totp_config_file_reset(PluginState* const plugin_state) {
|
|||||||
|
|
||||||
bool totp_config_file_update_encryption(
|
bool totp_config_file_update_encryption(
|
||||||
PluginState* plugin_state,
|
PluginState* plugin_state,
|
||||||
|
uint8_t new_crypto_key_slot,
|
||||||
const uint8_t* new_pin,
|
const uint8_t* new_pin,
|
||||||
uint8_t new_pin_length) {
|
uint8_t new_pin_length) {
|
||||||
FlipperFormat* config_file = plugin_state->config_file_context->config_file;
|
FlipperFormat* config_file = plugin_state->config_file_context->config_file;
|
||||||
@@ -489,23 +585,28 @@ bool totp_config_file_update_encryption(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t old_iv[TOTP_IV_SIZE];
|
if(!totp_crypto_check_key_slot(new_crypto_key_slot)) {
|
||||||
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
|
||||||
|
|
||||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
|
||||||
memset(&plugin_state->base_iv[0], 0, TOTP_IV_SIZE);
|
|
||||||
if(plugin_state->crypto_verify_data != NULL) {
|
|
||||||
free(plugin_state->crypto_verify_data);
|
|
||||||
plugin_state->crypto_verify_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CryptoSeedIVResult seed_result =
|
|
||||||
totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
|
|
||||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
|
||||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
|
||||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CryptoSettings old_crypto_settings = plugin_state->crypto_settings;
|
||||||
|
|
||||||
|
memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
|
||||||
|
memset(&plugin_state->crypto_settings.base_iv[0], 0, CRYPTO_IV_LENGTH);
|
||||||
|
if(plugin_state->crypto_settings.crypto_verify_data != NULL) {
|
||||||
|
free(plugin_state->crypto_settings.crypto_verify_data);
|
||||||
|
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_state->crypto_settings.crypto_key_slot = new_crypto_key_slot;
|
||||||
|
plugin_state->crypto_settings.crypto_version = CRYPTO_LATEST_VERSION;
|
||||||
|
|
||||||
|
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
|
||||||
|
&plugin_state->crypto_settings, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
|
||||||
|
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||||
|
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData &&
|
||||||
|
!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||||
|
return false;
|
||||||
} else if(seed_result == CryptoSeedIVResultFailed) {
|
} else if(seed_result == CryptoSeedIVResultFailed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -552,12 +653,15 @@ bool totp_config_file_update_encryption(
|
|||||||
|
|
||||||
size_t plain_token_length;
|
size_t plain_token_length;
|
||||||
uint8_t* plain_token = totp_crypto_decrypt(
|
uint8_t* plain_token = totp_crypto_decrypt(
|
||||||
encrypted_token, secret_bytes_count, &old_iv[0], &plain_token_length);
|
encrypted_token, secret_bytes_count, &old_crypto_settings, &plain_token_length);
|
||||||
|
|
||||||
free(encrypted_token);
|
free(encrypted_token);
|
||||||
size_t encrypted_token_length;
|
size_t encrypted_token_length;
|
||||||
encrypted_token = totp_crypto_encrypt(
|
encrypted_token = totp_crypto_encrypt(
|
||||||
plain_token, plain_token_length, &plugin_state->iv[0], &encrypted_token_length);
|
plain_token,
|
||||||
|
plain_token_length,
|
||||||
|
&plugin_state->crypto_settings,
|
||||||
|
&encrypted_token_length);
|
||||||
|
|
||||||
memset_s(plain_token, plain_token_length, 0, plain_token_length);
|
memset_s(plain_token, plain_token_length, 0, plain_token_length);
|
||||||
free(plain_token);
|
free(plain_token);
|
||||||
@@ -588,6 +692,36 @@ bool totp_config_file_update_encryption(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool totp_config_file_ensure_latest_encryption(
|
||||||
|
PluginState* plugin_state,
|
||||||
|
const uint8_t* pin,
|
||||||
|
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);
|
||||||
|
char* backup_path = totp_config_file_backup(plugin_state);
|
||||||
|
if(backup_path != NULL) {
|
||||||
|
free(backup_path);
|
||||||
|
uint8_t crypto_key_slot = plugin_state->crypto_settings.crypto_key_slot;
|
||||||
|
if(!totp_crypto_check_key_slot(crypto_key_slot)) {
|
||||||
|
crypto_key_slot = DEFAULT_CRYPTO_KEY_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
result =
|
||||||
|
totp_config_file_update_encryption(plugin_state, crypto_key_slot, pin, pin_length);
|
||||||
|
FURI_LOG_I(
|
||||||
|
LOGGING_TAG,
|
||||||
|
"Migration to crypto v%d is done. Result: %d",
|
||||||
|
CRYPTO_LATEST_VERSION,
|
||||||
|
result);
|
||||||
|
} else {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) {
|
TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) {
|
||||||
return plugin_state->config_file_context->token_info_iterator_context;
|
return plugin_state->config_file_context->token_info_iterator_context;
|
||||||
}
|
}
|
||||||
@@ -73,15 +73,29 @@ void totp_config_file_close(PluginState* const plugin_state);
|
|||||||
/**
|
/**
|
||||||
* @brief Updates config file encryption by re-encrypting it using new user's PIN and new randomly generated IV
|
* @brief Updates config file encryption by re-encrypting it using new user's PIN and new randomly generated IV
|
||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
|
* @param new_crypto_key_slot new crypto key slot to be used
|
||||||
* @param new_pin new user's PIN
|
* @param new_pin new user's PIN
|
||||||
* @param new_pin_length new user's PIN length
|
* @param new_pin_length new user's PIN length
|
||||||
* @return \c true if config file encryption successfully updated; \c false otherwise
|
* @return \c true if config file encryption successfully updated; \c false otherwise
|
||||||
*/
|
*/
|
||||||
bool totp_config_file_update_encryption(
|
bool totp_config_file_update_encryption(
|
||||||
PluginState* plugin_state,
|
PluginState* plugin_state,
|
||||||
|
uint8_t new_crypto_key_slot,
|
||||||
const uint8_t* new_pin,
|
const uint8_t* new_pin,
|
||||||
uint8_t new_pin_length);
|
uint8_t new_pin_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ensures application config file uses latest encryption and upgrades encryption if needed
|
||||||
|
* @param plugin_state application state
|
||||||
|
* @param pin user's PIN
|
||||||
|
* @param pin_length user's PIN length
|
||||||
|
* @return \c true if operation succeeded; \c false otherwise
|
||||||
|
*/
|
||||||
|
bool totp_config_file_ensure_latest_encryption(
|
||||||
|
PluginState* plugin_state,
|
||||||
|
const uint8_t* pin,
|
||||||
|
uint8_t pin_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets token info iterator context
|
* @brief Gets token info iterator context
|
||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
|
|
||||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
|
#define CONFIG_FILE_DIRECTORY_PATH STORAGE_APP_DATA_PATH_PREFIX
|
||||||
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
|
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
|
||||||
#define CONFIG_FILE_ACTUAL_VERSION (6)
|
#define CONFIG_FILE_ACTUAL_VERSION (8)
|
||||||
|
|
||||||
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
|
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
|
||||||
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
||||||
@@ -18,4 +18,7 @@
|
|||||||
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"
|
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"
|
||||||
#define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
|
#define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
|
||||||
#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
|
#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
|
||||||
|
#define TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT "AutomationKbLayout"
|
||||||
#define TOTP_CONFIG_KEY_FONT "Font"
|
#define TOTP_CONFIG_KEY_FONT "Font"
|
||||||
|
#define TOTP_CONFIG_KEY_CRYPTO_VERSION "CryptoVersion"
|
||||||
|
#define TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "CryptoKeySlot"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "common_migration.h"
|
#include "common_migration.h"
|
||||||
#include "../constants.h"
|
#include "../constants.h"
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
|
#include "../../../types/automation_kb_layout.h"
|
||||||
#include <flipper_format/flipper_format_i.h>
|
#include <flipper_format/flipper_format_i.h>
|
||||||
|
|
||||||
bool totp_config_migrate_to_latest(
|
bool totp_config_migrate_to_latest(
|
||||||
@@ -17,6 +18,28 @@ bool totp_config_migrate_to_latest(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(flipper_format_read_string(
|
||||||
|
fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str)) {
|
||||||
|
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str);
|
||||||
|
} else {
|
||||||
|
uint32_t old_crypto_version = 1;
|
||||||
|
flipper_format_write_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &old_crypto_version, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
flipper_format_rewind(fff_backup_data_file);
|
||||||
|
|
||||||
|
if(flipper_format_read_string(
|
||||||
|
fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str)) {
|
||||||
|
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str);
|
||||||
|
} else {
|
||||||
|
uint32_t default_old_key_slot = 2;
|
||||||
|
flipper_format_write_uint32(
|
||||||
|
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &default_old_key_slot, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
flipper_format_rewind(fff_backup_data_file);
|
||||||
|
|
||||||
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
|
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
|
||||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
|
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
|
||||||
}
|
}
|
||||||
@@ -68,6 +91,21 @@ bool totp_config_migrate_to_latest(
|
|||||||
|
|
||||||
flipper_format_rewind(fff_backup_data_file);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
flipper_format_rewind(fff_backup_data_file);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
if(!flipper_format_read_string(
|
if(!flipper_format_read_string(
|
||||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <flipper_format/flipper_format_stream.h>
|
#include <flipper_format/flipper_format_stream.h>
|
||||||
#include <toolbox/stream/file_stream.h>
|
#include <toolbox/stream/file_stream.h>
|
||||||
#include "../../types/common.h"
|
#include "../../types/common.h"
|
||||||
|
#include "../../types/crypto_settings.h"
|
||||||
|
|
||||||
#define CONFIG_FILE_PART_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf.part"
|
#define CONFIG_FILE_PART_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf.part"
|
||||||
#define STREAM_COPY_BUFFER_SIZE 128
|
#define STREAM_COPY_BUFFER_SIZE 128
|
||||||
@@ -15,7 +16,7 @@ struct TokenInfoIteratorContext {
|
|||||||
size_t last_seek_index;
|
size_t last_seek_index;
|
||||||
TokenInfo* current_token;
|
TokenInfo* current_token;
|
||||||
FlipperFormat* config_file;
|
FlipperFormat* config_file;
|
||||||
uint8_t* iv;
|
CryptoSettings* crypto_settings;
|
||||||
Storage* storage;
|
Storage* storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -237,8 +238,10 @@ static bool
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenInfoIteratorContext*
|
TokenInfoIteratorContext* totp_token_info_iterator_alloc(
|
||||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv) {
|
Storage* storage,
|
||||||
|
FlipperFormat* config_file,
|
||||||
|
CryptoSettings* crypto_settings) {
|
||||||
Stream* stream = flipper_format_get_raw_stream(config_file);
|
Stream* stream = flipper_format_get_raw_stream(config_file);
|
||||||
stream_rewind(stream);
|
stream_rewind(stream);
|
||||||
size_t tokens_count = 0;
|
size_t tokens_count = 0;
|
||||||
@@ -256,7 +259,7 @@ TokenInfoIteratorContext*
|
|||||||
context->total_count = tokens_count;
|
context->total_count = tokens_count;
|
||||||
context->current_token = token_info_alloc();
|
context->current_token = token_info_alloc();
|
||||||
context->config_file = config_file;
|
context->config_file = config_file;
|
||||||
context->iv = iv;
|
context->crypto_settings = crypto_settings;
|
||||||
context->storage = storage;
|
context->storage = storage;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@@ -453,7 +456,7 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to
|
|||||||
furi_string_get_cstr(temp_str),
|
furi_string_get_cstr(temp_str),
|
||||||
furi_string_size(temp_str),
|
furi_string_size(temp_str),
|
||||||
PlainTokenSecretEncodingBase32,
|
PlainTokenSecretEncodingBase32,
|
||||||
context->iv)) {
|
context->crypto_settings)) {
|
||||||
FURI_LOG_W(
|
FURI_LOG_W(
|
||||||
LOGGING_TAG,
|
LOGGING_TAG,
|
||||||
"Token \"%s\" has plain secret",
|
"Token \"%s\" has plain secret",
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ enum TotpIteratorUpdateTokenResults {
|
|||||||
* @brief Initializes a new token info iterator
|
* @brief Initializes a new token info iterator
|
||||||
* @param storage storage reference
|
* @param storage storage reference
|
||||||
* @param config_file config file to use
|
* @param config_file config file to use
|
||||||
* @param iv initialization vector (IV) to be used for encryption\decryption
|
* @param crypto_settings crypto settings
|
||||||
* @return Token info iterator context
|
* @return Token info iterator context
|
||||||
*/
|
*/
|
||||||
TokenInfoIteratorContext*
|
TokenInfoIteratorContext* totp_token_info_iterator_alloc(
|
||||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv);
|
Storage* storage,
|
||||||
|
FlipperFormat* config_file,
|
||||||
|
CryptoSettings* crypto_settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Navigates iterator to the token with given index
|
* @brief Navigates iterator to the token with given index
|
||||||
|
|||||||
23
applications/external/totp/services/crypto/common_types.h
vendored
Normal file
23
applications/external/totp/services/crypto/common_types.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint8_t CryptoSeedIVResult;
|
||||||
|
|
||||||
|
enum CryptoSeedIVResults {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IV seeding operation failed
|
||||||
|
*/
|
||||||
|
CryptoSeedIVResultFailed = 0b00,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IV seeding operation succeeded
|
||||||
|
*/
|
||||||
|
CryptoSeedIVResultFlagSuccess = 0b01,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief As a part of IV seeding operation new crypto verify data has been generated
|
||||||
|
*/
|
||||||
|
CryptoSeedIVResultFlagNewCryptoVerifyData = 0b10
|
||||||
|
};
|
||||||
11
applications/external/totp/services/crypto/constants.h
vendored
Normal file
11
applications/external/totp/services/crypto/constants.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CRYPTO_IV_LENGTH (16)
|
||||||
|
|
||||||
|
// According to this explanation: https://github.com/flipperdevices/flipperzero-firmware/issues/2885#issuecomment-1646664666
|
||||||
|
// disabling usage of any key which is "the same across all devices"
|
||||||
|
#define ACCEPTABLE_CRYPTO_KEY_SLOT_START (12)
|
||||||
|
#define ACCEPTABLE_CRYPTO_KEY_SLOT_END (100)
|
||||||
|
|
||||||
|
#define DEFAULT_CRYPTO_KEY_SLOT ACCEPTABLE_CRYPTO_KEY_SLOT_START
|
||||||
|
#define CRYPTO_LATEST_VERSION (2)
|
||||||
78
applications/external/totp/services/crypto/crypto_facade.c
vendored
Normal file
78
applications/external/totp/services/crypto/crypto_facade.c
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include "crypto_facade.h"
|
||||||
|
#include <furi_hal_crypto.h>
|
||||||
|
#include <furi/core/check.h>
|
||||||
|
#include "crypto_v1.h"
|
||||||
|
#include "crypto_v2.h"
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
bool totp_crypto_check_key_slot(uint8_t key_slot) {
|
||||||
|
uint8_t empty_iv[CRYPTO_IV_LENGTH] = {0};
|
||||||
|
if(key_slot < ACCEPTABLE_CRYPTO_KEY_SLOT_START || key_slot > ACCEPTABLE_CRYPTO_KEY_SLOT_END) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return furi_hal_crypto_verify_key(key_slot) &&
|
||||||
|
furi_hal_crypto_store_load_key(key_slot, empty_iv) &&
|
||||||
|
furi_hal_crypto_store_unload_key(key_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* totp_crypto_encrypt(
|
||||||
|
const uint8_t* plain_data,
|
||||||
|
const size_t plain_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* encrypted_data_length) {
|
||||||
|
if(crypto_settings->crypto_version == 1) {
|
||||||
|
return totp_crypto_encrypt_v1(
|
||||||
|
plain_data, plain_data_length, crypto_settings, encrypted_data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(crypto_settings->crypto_version == 2) {
|
||||||
|
return totp_crypto_encrypt_v2(
|
||||||
|
plain_data, plain_data_length, crypto_settings, encrypted_data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_crash("Unsupported crypto version");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* totp_crypto_decrypt(
|
||||||
|
const uint8_t* encrypted_data,
|
||||||
|
const size_t encrypted_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* decrypted_data_length) {
|
||||||
|
if(crypto_settings->crypto_version == 1) {
|
||||||
|
return totp_crypto_decrypt_v1(
|
||||||
|
encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(crypto_settings->crypto_version == 2) {
|
||||||
|
return totp_crypto_decrypt_v2(
|
||||||
|
encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_crash("Unsupported crypto version");
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoSeedIVResult
|
||||||
|
totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length) {
|
||||||
|
if(crypto_settings->crypto_version == 1) {
|
||||||
|
return totp_crypto_seed_iv_v1(crypto_settings, pin, pin_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(crypto_settings->crypto_version == 2) {
|
||||||
|
return totp_crypto_seed_iv_v2(crypto_settings, pin, pin_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_crash("Unsupported crypto version");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool totp_crypto_verify_key(const CryptoSettings* crypto_settings) {
|
||||||
|
if(crypto_settings->crypto_version == 1) {
|
||||||
|
return totp_crypto_verify_key_v1(crypto_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(crypto_settings->crypto_version == 2) {
|
||||||
|
return totp_crypto_verify_key_v2(crypto_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_crash("Unsupported crypto version");
|
||||||
|
}
|
||||||
@@ -1,68 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../types/plugin_state.h"
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../../types/crypto_settings.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
typedef uint8_t CryptoSeedIVResult;
|
/**
|
||||||
|
* @brief Checks whether key slot can be used for encryption purposes
|
||||||
enum CryptoSeedIVResults {
|
* @param key_slot key slot index
|
||||||
|
* @return \c true if key slot can be used for encryption; \c false otherwise
|
||||||
/**
|
|
||||||
* @brief IV seeding operation failed
|
|
||||||
*/
|
*/
|
||||||
CryptoSeedIVResultFailed = 0b00,
|
bool totp_crypto_check_key_slot(uint8_t key_slot);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief IV seeding operation succeeded
|
|
||||||
*/
|
|
||||||
CryptoSeedIVResultFlagSuccess = 0b01,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief As a part of IV seeding operation new crypto verify data has been generated
|
|
||||||
*/
|
|
||||||
CryptoSeedIVResultFlagNewCryptoVerifyData = 0b10
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||||
* @param plain_data plain data to be encrypted
|
* @param plain_data plain data to be encrypted
|
||||||
* @param plain_data_length plain data length
|
* @param plain_data_length plain data length
|
||||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
* @param crypto_settings crypto settings
|
||||||
* @param[out] encrypted_data_length encrypted data length
|
* @param[out] encrypted_data_length encrypted data length
|
||||||
* @return Encrypted data
|
* @return Encrypted data
|
||||||
*/
|
*/
|
||||||
uint8_t* totp_crypto_encrypt(
|
uint8_t* totp_crypto_encrypt(
|
||||||
const uint8_t* plain_data,
|
const uint8_t* plain_data,
|
||||||
const size_t plain_data_length,
|
const size_t plain_data_length,
|
||||||
const uint8_t* iv,
|
const CryptoSettings* crypto_settings,
|
||||||
size_t* encrypted_data_length);
|
size_t* encrypted_data_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||||
* @param encrypted_data encrypted data to be decrypted
|
* @param encrypted_data encrypted data to be decrypted
|
||||||
* @param encrypted_data_length encrypted data length
|
* @param encrypted_data_length encrypted data length
|
||||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
* @param crypto_settings crypto settings
|
||||||
* @param[out] decrypted_data_length decrypted data length
|
* @param[out] decrypted_data_length decrypted data length
|
||||||
* @return Decrypted data
|
* @return Decrypted data
|
||||||
*/
|
*/
|
||||||
uint8_t* totp_crypto_decrypt(
|
uint8_t* totp_crypto_decrypt(
|
||||||
const uint8_t* encrypted_data,
|
const uint8_t* encrypted_data,
|
||||||
const size_t encrypted_data_length,
|
const size_t encrypted_data_length,
|
||||||
const uint8_t* iv,
|
const CryptoSettings* crypto_settings,
|
||||||
size_t* decrypted_data_length);
|
size_t* decrypted_data_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Seed initialization vector (IV) using user's PIN
|
* @brief Seed initialization vector (IV) using user's PIN
|
||||||
* @param plugin_state application state
|
* @param crypto_settings crypto settings
|
||||||
* @param pin user's PIN
|
* @param pin user's PIN
|
||||||
* @param pin_length user's PIN length
|
* @param pin_length user's PIN length
|
||||||
* @return Results of seeding IV
|
* @return Results of seeding IV
|
||||||
*/
|
*/
|
||||||
CryptoSeedIVResult
|
CryptoSeedIVResult
|
||||||
totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length);
|
totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||||
* @param plugin_state application state
|
* @param crypto_settings crypto settings
|
||||||
* @return \c true if cryptographic information is valid; \c false otherwise
|
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||||
*/
|
*/
|
||||||
bool totp_crypto_verify_key(const PluginState* plugin_state);
|
bool totp_crypto_verify_key(const CryptoSettings* crypto_settings);
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "crypto.h"
|
#include "crypto_v1.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <furi.h>
|
||||||
#include <furi_hal_crypto.h>
|
#include <furi_hal_crypto.h>
|
||||||
#include <furi_hal_random.h>
|
#include <furi_hal_random.h>
|
||||||
#include <furi_hal_version.h>
|
#include <furi_hal_version.h>
|
||||||
@@ -8,13 +10,14 @@
|
|||||||
#define CRYPTO_KEY_SLOT (2)
|
#define CRYPTO_KEY_SLOT (2)
|
||||||
#define CRYPTO_VERIFY_KEY_LENGTH (16)
|
#define CRYPTO_VERIFY_KEY_LENGTH (16)
|
||||||
#define CRYPTO_ALIGNMENT_FACTOR (16)
|
#define CRYPTO_ALIGNMENT_FACTOR (16)
|
||||||
|
#define TOTP_IV_SIZE (16)
|
||||||
|
|
||||||
static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass";
|
static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass";
|
||||||
|
|
||||||
uint8_t* totp_crypto_encrypt(
|
uint8_t* totp_crypto_encrypt_v1(
|
||||||
const uint8_t* plain_data,
|
const uint8_t* plain_data,
|
||||||
const size_t plain_data_length,
|
const size_t plain_data_length,
|
||||||
const uint8_t* iv,
|
const CryptoSettings* crypto_settings,
|
||||||
size_t* encrypted_data_length) {
|
size_t* encrypted_data_length) {
|
||||||
uint8_t* encrypted_data;
|
uint8_t* encrypted_data;
|
||||||
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
|
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
|
||||||
@@ -29,7 +32,7 @@ uint8_t* totp_crypto_encrypt(
|
|||||||
furi_check(encrypted_data != NULL);
|
furi_check(encrypted_data != NULL);
|
||||||
*encrypted_data_length = plain_data_aligned_length;
|
*encrypted_data_length = plain_data_aligned_length;
|
||||||
|
|
||||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||||
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length);
|
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length);
|
||||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ uint8_t* totp_crypto_encrypt(
|
|||||||
furi_check(encrypted_data != NULL);
|
furi_check(encrypted_data != NULL);
|
||||||
*encrypted_data_length = plain_data_length;
|
*encrypted_data_length = plain_data_length;
|
||||||
|
|
||||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||||
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length);
|
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length);
|
||||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||||
}
|
}
|
||||||
@@ -48,29 +51,31 @@ uint8_t* totp_crypto_encrypt(
|
|||||||
return encrypted_data;
|
return encrypted_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* totp_crypto_decrypt(
|
uint8_t* totp_crypto_decrypt_v1(
|
||||||
const uint8_t* encrypted_data,
|
const uint8_t* encrypted_data,
|
||||||
const size_t encrypted_data_length,
|
const size_t encrypted_data_length,
|
||||||
const uint8_t* iv,
|
const CryptoSettings* crypto_settings,
|
||||||
size_t* decrypted_data_length) {
|
size_t* decrypted_data_length) {
|
||||||
*decrypted_data_length = encrypted_data_length;
|
*decrypted_data_length = encrypted_data_length;
|
||||||
uint8_t* decrypted_data = malloc(*decrypted_data_length);
|
uint8_t* decrypted_data = malloc(*decrypted_data_length);
|
||||||
furi_check(decrypted_data != NULL);
|
furi_check(decrypted_data != NULL);
|
||||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||||
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length);
|
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length);
|
||||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||||
return decrypted_data;
|
return decrypted_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoSeedIVResult
|
CryptoSeedIVResult totp_crypto_seed_iv_v1(
|
||||||
totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
|
CryptoSettings* crypto_settings,
|
||||||
|
const uint8_t* pin,
|
||||||
|
uint8_t pin_length) {
|
||||||
CryptoSeedIVResult result;
|
CryptoSeedIVResult result;
|
||||||
if(plugin_state->crypto_verify_data == NULL) {
|
if(crypto_settings->crypto_verify_data == NULL) {
|
||||||
FURI_LOG_I(LOGGING_TAG, "Generating new IV");
|
FURI_LOG_I(LOGGING_TAG, "Generating new IV");
|
||||||
furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
|
furi_hal_random_fill_buf(&crypto_settings->base_iv[0], TOTP_IV_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE);
|
memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], TOTP_IV_SIZE);
|
||||||
if(pin != NULL && pin_length > 0) {
|
if(pin != NULL && pin_length > 0) {
|
||||||
uint8_t max_i;
|
uint8_t max_i;
|
||||||
if(pin_length > TOTP_IV_SIZE) {
|
if(pin_length > TOTP_IV_SIZE) {
|
||||||
@@ -80,7 +85,7 @@ CryptoSeedIVResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(uint8_t i = 0; i < max_i; i++) {
|
for(uint8_t i = 0; i < max_i; i++) {
|
||||||
plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
|
crypto_settings->iv[i] = crypto_settings->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t max_i;
|
uint8_t max_i;
|
||||||
@@ -93,24 +98,24 @@ CryptoSeedIVResult
|
|||||||
|
|
||||||
const uint8_t* uid = (const uint8_t*)UID64_BASE; //-V566
|
const uint8_t* uid = (const uint8_t*)UID64_BASE; //-V566
|
||||||
for(uint8_t i = 0; i < max_i; i++) {
|
for(uint8_t i = 0; i < max_i; i++) {
|
||||||
plugin_state->iv[i] = plugin_state->iv[i] ^ uid[i];
|
crypto_settings->iv[i] = crypto_settings->iv[i] ^ uid[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = CryptoSeedIVResultFlagSuccess;
|
result = CryptoSeedIVResultFlagSuccess;
|
||||||
if(plugin_state->crypto_verify_data == NULL) {
|
if(crypto_settings->crypto_verify_data == NULL) {
|
||||||
FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data");
|
FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data");
|
||||||
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
|
crypto_settings->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
|
||||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
furi_check(crypto_settings->crypto_verify_data != NULL);
|
||||||
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
crypto_settings->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
||||||
|
|
||||||
plugin_state->crypto_verify_data = totp_crypto_encrypt(
|
crypto_settings->crypto_verify_data = totp_crypto_encrypt_v1(
|
||||||
(const uint8_t*)CRYPTO_VERIFY_KEY,
|
(const uint8_t*)CRYPTO_VERIFY_KEY,
|
||||||
CRYPTO_VERIFY_KEY_LENGTH,
|
CRYPTO_VERIFY_KEY_LENGTH,
|
||||||
&plugin_state->iv[0],
|
crypto_settings,
|
||||||
&plugin_state->crypto_verify_data_length);
|
&crypto_settings->crypto_verify_data_length);
|
||||||
|
|
||||||
plugin_state->pin_set = pin != NULL && pin_length > 0;
|
crypto_settings->pin_required = pin != NULL && pin_length > 0;
|
||||||
|
|
||||||
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||||
}
|
}
|
||||||
@@ -118,12 +123,12 @@ CryptoSeedIVResult
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool totp_crypto_verify_key(const PluginState* plugin_state) {
|
bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings) {
|
||||||
size_t decrypted_key_length;
|
size_t decrypted_key_length;
|
||||||
uint8_t* decrypted_key = totp_crypto_decrypt(
|
uint8_t* decrypted_key = totp_crypto_decrypt_v1(
|
||||||
plugin_state->crypto_verify_data,
|
crypto_settings->crypto_verify_data,
|
||||||
plugin_state->crypto_verify_data_length,
|
crypto_settings->crypto_verify_data_length,
|
||||||
&plugin_state->iv[0],
|
crypto_settings,
|
||||||
&decrypted_key_length);
|
&decrypted_key_length);
|
||||||
|
|
||||||
bool key_valid = true;
|
bool key_valid = true;
|
||||||
52
applications/external/totp/services/crypto/crypto_v1.h
vendored
Normal file
52
applications/external/totp/services/crypto/crypto_v1.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../../types/crypto_settings.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||||
|
* @param plain_data plain data to be encrypted
|
||||||
|
* @param plain_data_length plain data length
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param[out] encrypted_data_length encrypted data length
|
||||||
|
* @return Encrypted data
|
||||||
|
*/
|
||||||
|
uint8_t* totp_crypto_encrypt_v1(
|
||||||
|
const uint8_t* plain_data,
|
||||||
|
const size_t plain_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* encrypted_data_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||||
|
* @param encrypted_data encrypted data to be decrypted
|
||||||
|
* @param encrypted_data_length encrypted data length
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param[out] decrypted_data_length decrypted data length
|
||||||
|
* @return Decrypted data
|
||||||
|
*/
|
||||||
|
uint8_t* totp_crypto_decrypt_v1(
|
||||||
|
const uint8_t* encrypted_data,
|
||||||
|
const size_t encrypted_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* decrypted_data_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Seed initialization vector (IV) using user's PIN
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param pin user's PIN
|
||||||
|
* @param pin_length user's PIN length
|
||||||
|
* @return Results of seeding IV
|
||||||
|
*/
|
||||||
|
CryptoSeedIVResult
|
||||||
|
totp_crypto_seed_iv_v1(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||||
|
*/
|
||||||
|
bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings);
|
||||||
184
applications/external/totp/services/crypto/crypto_v2.c
vendored
Normal file
184
applications/external/totp/services/crypto/crypto_v2.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#include "crypto_v2.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal_crypto.h>
|
||||||
|
#include <furi_hal_random.h>
|
||||||
|
#include <furi_hal_version.h>
|
||||||
|
#include "../../types/common.h"
|
||||||
|
#include "../hmac/hmac_sha512.h"
|
||||||
|
#include "memset_s.h"
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
#define CRYPTO_ALIGNMENT_FACTOR (16)
|
||||||
|
|
||||||
|
static const uint8_t* get_device_uid() {
|
||||||
|
return (const uint8_t*)UID64_BASE; //-V566
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t get_device_uid_length() {
|
||||||
|
return furi_hal_version_uid_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t* get_crypto_verify_key() {
|
||||||
|
return get_device_uid();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t get_crypto_verify_key_length() {
|
||||||
|
return get_device_uid_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* totp_crypto_encrypt_v2(
|
||||||
|
const uint8_t* plain_data,
|
||||||
|
const size_t plain_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* encrypted_data_length) {
|
||||||
|
uint8_t* encrypted_data;
|
||||||
|
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
|
||||||
|
if(remain) {
|
||||||
|
size_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR;
|
||||||
|
uint8_t* plain_data_aligned = malloc(plain_data_aligned_length);
|
||||||
|
furi_check(plain_data_aligned != NULL);
|
||||||
|
memset(plain_data_aligned, 0, plain_data_aligned_length);
|
||||||
|
memcpy(plain_data_aligned, plain_data, plain_data_length);
|
||||||
|
|
||||||
|
encrypted_data = malloc(plain_data_aligned_length);
|
||||||
|
furi_check(encrypted_data != NULL);
|
||||||
|
*encrypted_data_length = plain_data_aligned_length;
|
||||||
|
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||||
|
"Encryption failed: store_load_key");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length),
|
||||||
|
"Encryption failed: encrypt");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||||
|
"Encryption failed: store_unload_key");
|
||||||
|
|
||||||
|
memset_s(plain_data_aligned, plain_data_aligned_length, 0, plain_data_aligned_length);
|
||||||
|
free(plain_data_aligned);
|
||||||
|
} else {
|
||||||
|
encrypted_data = malloc(plain_data_length);
|
||||||
|
furi_check(encrypted_data != NULL);
|
||||||
|
*encrypted_data_length = plain_data_length;
|
||||||
|
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||||
|
"Encryption failed: store_load_key");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length),
|
||||||
|
"Encryption failed: encrypt");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||||
|
"Encryption failed: store_unload_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return encrypted_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* totp_crypto_decrypt_v2(
|
||||||
|
const uint8_t* encrypted_data,
|
||||||
|
const size_t encrypted_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* decrypted_data_length) {
|
||||||
|
*decrypted_data_length = encrypted_data_length;
|
||||||
|
uint8_t* decrypted_data = malloc(*decrypted_data_length);
|
||||||
|
furi_check(decrypted_data != NULL);
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||||
|
"Decryption failed: store_load_key");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length),
|
||||||
|
"Decryption failed: decrypt");
|
||||||
|
furi_check(
|
||||||
|
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||||
|
"Decryption failed: store_unload_key");
|
||||||
|
return decrypted_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoSeedIVResult totp_crypto_seed_iv_v2(
|
||||||
|
CryptoSettings* crypto_settings,
|
||||||
|
const uint8_t* pin,
|
||||||
|
uint8_t pin_length) {
|
||||||
|
CryptoSeedIVResult result;
|
||||||
|
if(crypto_settings->crypto_verify_data == NULL) {
|
||||||
|
FURI_LOG_I(LOGGING_TAG, "Generating new IV");
|
||||||
|
furi_hal_random_fill_buf(&crypto_settings->base_iv[0], CRYPTO_IV_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH);
|
||||||
|
|
||||||
|
const uint8_t* device_uid = get_device_uid();
|
||||||
|
uint8_t device_uid_length = get_device_uid_length();
|
||||||
|
|
||||||
|
uint8_t hmac_key_length = device_uid_length;
|
||||||
|
if(pin != NULL && pin_length > 0) {
|
||||||
|
hmac_key_length += pin_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* hmac_key = malloc(hmac_key_length);
|
||||||
|
furi_check(hmac_key != NULL);
|
||||||
|
|
||||||
|
memcpy(hmac_key, device_uid, device_uid_length);
|
||||||
|
|
||||||
|
if(pin != NULL && pin_length > 0) {
|
||||||
|
memcpy(hmac_key + device_uid_length, pin, pin_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hmac[HMAC_SHA512_RESULT_SIZE] = {0};
|
||||||
|
int hmac_result_code = hmac_sha512(
|
||||||
|
hmac_key, hmac_key_length, &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH, &hmac[0]);
|
||||||
|
|
||||||
|
memset_s(hmac_key, hmac_key_length, 0, hmac_key_length);
|
||||||
|
free(hmac_key);
|
||||||
|
|
||||||
|
if(hmac_result_code == 0) {
|
||||||
|
uint8_t offset =
|
||||||
|
hmac[HMAC_SHA512_RESULT_SIZE - 1] % (HMAC_SHA512_RESULT_SIZE - CRYPTO_IV_LENGTH - 1);
|
||||||
|
memcpy(&crypto_settings->iv[0], &hmac[offset], CRYPTO_IV_LENGTH);
|
||||||
|
|
||||||
|
result = CryptoSeedIVResultFlagSuccess;
|
||||||
|
if(crypto_settings->crypto_verify_data == NULL) {
|
||||||
|
const uint8_t* crypto_vkey = get_crypto_verify_key();
|
||||||
|
uint8_t crypto_vkey_length = get_crypto_verify_key_length();
|
||||||
|
FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data");
|
||||||
|
crypto_settings->crypto_verify_data = malloc(crypto_vkey_length);
|
||||||
|
furi_check(crypto_settings->crypto_verify_data != NULL);
|
||||||
|
crypto_settings->crypto_verify_data_length = crypto_vkey_length;
|
||||||
|
|
||||||
|
crypto_settings->crypto_verify_data = totp_crypto_encrypt_v2(
|
||||||
|
crypto_vkey,
|
||||||
|
crypto_vkey_length,
|
||||||
|
crypto_settings,
|
||||||
|
&crypto_settings->crypto_verify_data_length);
|
||||||
|
|
||||||
|
crypto_settings->pin_required = pin != NULL && pin_length > 0;
|
||||||
|
|
||||||
|
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = CryptoSeedIVResultFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings) {
|
||||||
|
size_t decrypted_key_length;
|
||||||
|
uint8_t* decrypted_key = totp_crypto_decrypt_v2(
|
||||||
|
crypto_settings->crypto_verify_data,
|
||||||
|
crypto_settings->crypto_verify_data_length,
|
||||||
|
crypto_settings,
|
||||||
|
&decrypted_key_length);
|
||||||
|
|
||||||
|
const uint8_t* crypto_vkey = get_crypto_verify_key();
|
||||||
|
uint8_t crypto_vkey_length = get_crypto_verify_key_length();
|
||||||
|
bool key_valid = true;
|
||||||
|
for(uint8_t i = 0; i < crypto_vkey_length && key_valid; i++) {
|
||||||
|
if(decrypted_key[i] != crypto_vkey[i]) key_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(decrypted_key);
|
||||||
|
|
||||||
|
return key_valid;
|
||||||
|
}
|
||||||
52
applications/external/totp/services/crypto/crypto_v2.h
vendored
Normal file
52
applications/external/totp/services/crypto/crypto_v2.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../../types/crypto_settings.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||||
|
* @param plain_data plain data to be encrypted
|
||||||
|
* @param plain_data_length plain data length
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param[out] encrypted_data_length encrypted data length
|
||||||
|
* @return Encrypted data
|
||||||
|
*/
|
||||||
|
uint8_t* totp_crypto_encrypt_v2(
|
||||||
|
const uint8_t* plain_data,
|
||||||
|
const size_t plain_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* encrypted_data_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||||
|
* @param encrypted_data encrypted data to be decrypted
|
||||||
|
* @param encrypted_data_length encrypted data length
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param[out] decrypted_data_length decrypted data length
|
||||||
|
* @return Decrypted data
|
||||||
|
*/
|
||||||
|
uint8_t* totp_crypto_decrypt_v2(
|
||||||
|
const uint8_t* encrypted_data,
|
||||||
|
const size_t encrypted_data_length,
|
||||||
|
const CryptoSettings* crypto_settings,
|
||||||
|
size_t* decrypted_data_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Seed initialization vector (IV) using user's PIN
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @param pin user's PIN
|
||||||
|
* @param pin_length user's PIN length
|
||||||
|
* @return Results of seeding IV
|
||||||
|
*/
|
||||||
|
CryptoSeedIVResult
|
||||||
|
totp_crypto_seed_iv_v2(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||||
|
* @param crypto_settings crypto settings
|
||||||
|
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||||
|
*/
|
||||||
|
bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings);
|
||||||
134
applications/external/totp/totp_app.c
vendored
134
applications/external/totp/totp_app.c
vendored
@@ -15,27 +15,32 @@
|
|||||||
#include "ui/scene_director.h"
|
#include "ui/scene_director.h"
|
||||||
#include "ui/constants.h"
|
#include "ui/constants.h"
|
||||||
#include "ui/common_dialogs.h"
|
#include "ui/common_dialogs.h"
|
||||||
#include "services/crypto/crypto.h"
|
#include "services/crypto/crypto_facade.h"
|
||||||
#include "cli/cli.h"
|
#include "cli/cli.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
struct TotpRenderCallbackContext {
|
||||||
|
FuriMutex* mutex;
|
||||||
|
PluginState* plugin_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void render_callback(Canvas* const canvas, void* const ctx) {
|
||||||
furi_assert(ctx);
|
furi_assert(ctx);
|
||||||
PluginState* plugin_state = ctx;
|
const struct TotpRenderCallbackContext* context = ctx;
|
||||||
if(furi_mutex_acquire(plugin_state->mutex, 25) == FuriStatusOk) {
|
if(furi_mutex_acquire(context->mutex, 25) == FuriStatusOk) {
|
||||||
totp_scene_director_render(canvas, plugin_state);
|
totp_scene_director_render(canvas, context->plugin_state);
|
||||||
furi_mutex_release(plugin_state->mutex);
|
furi_mutex_release(context->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
static void input_callback(InputEvent* const input_event, void* const ctx) {
|
||||||
furi_assert(event_queue);
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* event_queue = ctx;
|
||||||
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
static bool first_run_init(PluginState* const plugin_state) {
|
||||||
if(plugin_state->crypto_verify_data == NULL) {
|
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
dialog_message_set_buttons(message, "No", NULL, "Yes");
|
dialog_message_set_buttons(message, "No", NULL, "Yes");
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
@@ -45,13 +50,18 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
|||||||
SCREEN_HEIGHT_CENTER,
|
SCREEN_HEIGHT_CENTER,
|
||||||
AlignCenter,
|
AlignCenter,
|
||||||
AlignCenter);
|
AlignCenter);
|
||||||
DialogMessageButton dialog_result =
|
DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs_app, message);
|
||||||
dialog_message_show(plugin_state->dialogs_app, message);
|
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
|
if(!totp_crypto_check_key_slot(plugin_state->crypto_settings.crypto_key_slot)) {
|
||||||
|
totp_dialogs_config_loading_error(plugin_state);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(dialog_result == DialogMessageButtonRight) {
|
if(dialog_result == DialogMessageButtonRight) {
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||||
} else {
|
} else {
|
||||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0);
|
CryptoSeedIVResult seed_result =
|
||||||
|
totp_crypto_seed_iv(&plugin_state->crypto_settings, NULL, 0);
|
||||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||||
@@ -65,10 +75,12 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
|||||||
|
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
}
|
}
|
||||||
} else if(plugin_state->pin_set) {
|
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
return true;
|
||||||
} else {
|
}
|
||||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0);
|
|
||||||
|
static bool pinless_activation(PluginState* const plugin_state) {
|
||||||
|
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(&plugin_state->crypto_settings, NULL, 0);
|
||||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||||
@@ -80,12 +92,13 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(totp_crypto_verify_key(plugin_state)) {
|
if(totp_crypto_verify_key(&plugin_state->crypto_settings)) {
|
||||||
|
totp_config_file_ensure_latest_encryption(plugin_state, NULL, 0);
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(
|
FURI_LOG_E(
|
||||||
LOGGING_TAG,
|
LOGGING_TAG,
|
||||||
"Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other");
|
"Digital signature verification failed. Looks like conf file was created on another device and can't be used on any other");
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
dialog_message_set_buttons(message, "Exit", NULL, NULL);
|
dialog_message_set_buttons(message, "Exit", NULL, NULL);
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
@@ -99,6 +112,28 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
|||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pin_activation(PluginState* const plugin_state) {
|
||||||
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
||||||
|
if(plugin_state->crypto_settings.crypto_verify_data == NULL) {
|
||||||
|
if(!first_run_init(plugin_state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if(plugin_state->crypto_settings.pin_required) {
|
||||||
|
if(!pin_activation(plugin_state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!pinless_activation(plugin_state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -109,6 +144,7 @@ static bool on_user_idle(void* context) {
|
|||||||
if(plugin_state->current_scene != TotpSceneAuthentication &&
|
if(plugin_state->current_scene != TotpSceneAuthentication &&
|
||||||
plugin_state->current_scene != TotpSceneStandby) {
|
plugin_state->current_scene != TotpSceneStandby) {
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||||
|
totp_scene_director_force_redraw(plugin_state);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,18 +153,17 @@ static bool on_user_idle(void* context) {
|
|||||||
|
|
||||||
static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||||
plugin_state->gui = furi_record_open(RECORD_GUI);
|
plugin_state->gui = furi_record_open(RECORD_GUI);
|
||||||
plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
||||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
|
||||||
|
|
||||||
if(!totp_config_file_load(plugin_state)) {
|
if(!totp_config_file_load(plugin_state)) {
|
||||||
totp_dialogs_config_loading_error(plugin_state);
|
totp_dialogs_config_loading_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
plugin_state->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
||||||
plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init();
|
plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init();
|
||||||
} else {
|
} else {
|
||||||
@@ -136,7 +171,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(plugin_state->pin_set) {
|
if(plugin_state->crypto_settings.pin_required) {
|
||||||
plugin_state->idle_timeout_context =
|
plugin_state->idle_timeout_context =
|
||||||
idle_timeout_alloc(TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC, &on_user_idle, plugin_state);
|
idle_timeout_alloc(TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC, &on_user_idle, plugin_state);
|
||||||
idle_timeout_start(plugin_state->idle_timeout_context);
|
idle_timeout_start(plugin_state->idle_timeout_context);
|
||||||
@@ -154,28 +189,35 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
furi_record_close(RECORD_GUI);
|
furi_record_close(RECORD_GUI);
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
|
||||||
totp_config_file_close(plugin_state);
|
totp_config_file_close(plugin_state);
|
||||||
|
|
||||||
if(plugin_state->crypto_verify_data != NULL) {
|
if(plugin_state->crypto_settings.crypto_verify_data != NULL) {
|
||||||
free(plugin_state->crypto_verify_data);
|
free(plugin_state->crypto_settings.crypto_verify_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(plugin_state->bt_type_code_worker_context != NULL) {
|
if(plugin_state->bt_type_code_worker_context != NULL) {
|
||||||
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
||||||
plugin_state->bt_type_code_worker_context = NULL;
|
plugin_state->bt_type_code_worker_context = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
furi_mutex_free(plugin_state->mutex);
|
if(plugin_state->event_queue != NULL) {
|
||||||
|
furi_message_queue_free(plugin_state->event_queue);
|
||||||
|
}
|
||||||
|
|
||||||
free(plugin_state);
|
free(plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t totp_app() {
|
int32_t totp_app() {
|
||||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
FURI_LOG_I(
|
||||||
|
LOGGING_TAG,
|
||||||
|
"App version: %" PRIu8 ".%" PRIu8 ".%" PRIu8,
|
||||||
|
TOTP_APP_VERSION_MAJOR,
|
||||||
|
TOTP_APP_VERSION_MINOR,
|
||||||
|
TOTP_APP_VERSION_PATCH);
|
||||||
PluginState* plugin_state = malloc(sizeof(PluginState));
|
PluginState* plugin_state = malloc(sizeof(PluginState));
|
||||||
furi_check(plugin_state != NULL);
|
furi_check(plugin_state != NULL);
|
||||||
|
|
||||||
@@ -185,7 +227,7 @@ int32_t totp_app() {
|
|||||||
return 254;
|
return 254;
|
||||||
}
|
}
|
||||||
|
|
||||||
TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state, event_queue);
|
TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state);
|
||||||
|
|
||||||
if(!totp_activate_initial_scene(plugin_state)) {
|
if(!totp_activate_initial_scene(plugin_state)) {
|
||||||
FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
|
FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
|
||||||
@@ -196,10 +238,14 @@ int32_t totp_app() {
|
|||||||
// Affecting dolphin level
|
// Affecting dolphin level
|
||||||
dolphin_deed(DolphinDeedPluginStart);
|
dolphin_deed(DolphinDeedPluginStart);
|
||||||
|
|
||||||
|
FuriMutex* main_loop_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||||
|
struct TotpRenderCallbackContext render_context = {
|
||||||
|
.plugin_state = plugin_state, .mutex = main_loop_mutex};
|
||||||
|
|
||||||
// Set system callbacks
|
// Set system callbacks
|
||||||
ViewPort* view_port = view_port_alloc();
|
ViewPort* view_port = view_port_alloc();
|
||||||
view_port_draw_callback_set(view_port, render_callback, plugin_state);
|
view_port_draw_callback_set(view_port, render_callback, &render_context);
|
||||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
view_port_input_callback_set(view_port, input_callback, plugin_state->event_queue);
|
||||||
|
|
||||||
// Open GUI and register view_port
|
// Open GUI and register view_port
|
||||||
gui_add_view_port(plugin_state->gui, view_port, GuiLayerFullscreen);
|
gui_add_view_port(plugin_state->gui, view_port, GuiLayerFullscreen);
|
||||||
@@ -207,24 +253,24 @@ int32_t totp_app() {
|
|||||||
PluginEvent event;
|
PluginEvent event;
|
||||||
bool processing = true;
|
bool processing = true;
|
||||||
while(processing) {
|
while(processing) {
|
||||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
if(furi_message_queue_get(plugin_state->event_queue, &event, FuriWaitForever) ==
|
||||||
|
FuriStatusOk) {
|
||||||
if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) == FuriStatusOk) {
|
if(event.type == EventForceCloseApp) {
|
||||||
if(event_status == FuriStatusOk) {
|
processing = false;
|
||||||
|
} else if(event.type == EventForceRedraw) {
|
||||||
|
processing = true; //-V1048
|
||||||
|
} else if(furi_mutex_acquire(main_loop_mutex, FuriWaitForever) == FuriStatusOk) {
|
||||||
if(event.type == EventTypeKey && plugin_state->idle_timeout_context != NULL) {
|
if(event.type == EventTypeKey && plugin_state->idle_timeout_context != NULL) {
|
||||||
idle_timeout_report_activity(plugin_state->idle_timeout_context);
|
idle_timeout_report_activity(plugin_state->idle_timeout_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.type == EventForceCloseApp) {
|
|
||||||
processing = false;
|
|
||||||
} else {
|
|
||||||
processing = totp_scene_director_handle_event(&event, plugin_state);
|
processing = totp_scene_director_handle_event(&event, plugin_state);
|
||||||
|
|
||||||
|
furi_mutex_release(main_loop_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view_port_update(view_port);
|
view_port_update(view_port);
|
||||||
furi_mutex_release(plugin_state->mutex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
totp_cli_unregister_command_handler(cli_context);
|
totp_cli_unregister_command_handler(cli_context);
|
||||||
@@ -233,7 +279,7 @@ int32_t totp_app() {
|
|||||||
view_port_enabled_set(view_port, false);
|
view_port_enabled_set(view_port, false);
|
||||||
gui_remove_view_port(plugin_state->gui, view_port);
|
gui_remove_view_port(plugin_state->gui, view_port);
|
||||||
view_port_free(view_port);
|
view_port_free(view_port);
|
||||||
furi_message_queue_free(event_queue);
|
furi_mutex_free(main_loop_mutex);
|
||||||
totp_plugin_state_free(plugin_state);
|
totp_plugin_state_free(plugin_state);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
8
applications/external/totp/types/automation_kb_layout.h
vendored
Normal file
8
applications/external/totp/types/automation_kb_layout.h
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef uint8_t AutomationKeyboardLayout;
|
||||||
|
|
||||||
|
enum AutomationKeyboardLayouts {
|
||||||
|
AutomationKeyboardLayoutQWERTY = 0,
|
||||||
|
AutomationKeyboardLayoutAZERTY = 1
|
||||||
|
};
|
||||||
@@ -7,7 +7,7 @@ typedef uint8_t AutomationMethod;
|
|||||||
enum AutomationMethods {
|
enum AutomationMethods {
|
||||||
AutomationMethodNone = 0b00,
|
AutomationMethodNone = 0b00,
|
||||||
AutomationMethodBadUsb = 0b01,
|
AutomationMethodBadUsb = 0b01,
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
AutomationMethodBadBt = 0b10,
|
AutomationMethodBadBt = 0b10,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
41
applications/external/totp/types/crypto_settings.h
vendored
Normal file
41
applications/external/totp/types/crypto_settings.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../services/crypto/constants.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief Crypto key slot to be used
|
||||||
|
*/
|
||||||
|
uint8_t crypto_key_slot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crypto algorithms version to be used
|
||||||
|
*/
|
||||||
|
uint8_t crypto_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialization vector (IV) to be used for encryption\decryption
|
||||||
|
*/
|
||||||
|
uint8_t iv[CRYPTO_IV_LENGTH];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Basic randomly-generated initialization vector (IV)
|
||||||
|
*/
|
||||||
|
uint8_t base_iv[CRYPTO_IV_LENGTH];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encrypted well-known data
|
||||||
|
*/
|
||||||
|
uint8_t* crypto_verify_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encrypted well-known data length
|
||||||
|
*/
|
||||||
|
size_t crypto_verify_data_length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether user's PIN is required or not
|
||||||
|
*/
|
||||||
|
bool pin_required;
|
||||||
|
} CryptoSettings;
|
||||||
@@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
typedef uint8_t EventType;
|
typedef uint8_t EventType;
|
||||||
|
|
||||||
enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp };
|
enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp, EventForceRedraw };
|
||||||
|
|||||||
58
applications/external/totp/types/plugin_state.h
vendored
58
applications/external/totp/types/plugin_state.h
vendored
@@ -9,11 +9,11 @@
|
|||||||
#include "../services/idle_timeout/idle_timeout.h"
|
#include "../services/idle_timeout/idle_timeout.h"
|
||||||
#include "notification_method.h"
|
#include "notification_method.h"
|
||||||
#include "automation_method.h"
|
#include "automation_method.h"
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#include "automation_kb_layout.h"
|
||||||
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
#include "../workers/bt_type_code/bt_type_code.h"
|
#include "../workers/bt_type_code/bt_type_code.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "crypto_settings.h"
|
||||||
#define TOTP_IV_SIZE (16)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Application state structure
|
* @brief Application state structure
|
||||||
@@ -29,11 +29,6 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
void* current_scene_state;
|
void* current_scene_state;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reference to the firmware notification subsystem
|
|
||||||
*/
|
|
||||||
NotificationApp* notification_app;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reference to the firmware dialogs subsystem
|
* @brief Reference to the firmware dialogs subsystem
|
||||||
*/
|
*/
|
||||||
@@ -54,47 +49,22 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
ConfigFileContext* config_file_context;
|
ConfigFileContext* config_file_context;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Encrypted well-known string data
|
|
||||||
*/
|
|
||||||
uint8_t* crypto_verify_data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Encrypted well-known string data length
|
|
||||||
*/
|
|
||||||
size_t crypto_verify_data_length;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Whether PIN is set by user or not
|
|
||||||
*/
|
|
||||||
bool pin_set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialization vector (IV) to be used for encryption\decryption
|
|
||||||
*/
|
|
||||||
uint8_t iv[TOTP_IV_SIZE];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Basic randomly-generated initialization vector (IV)
|
|
||||||
*/
|
|
||||||
uint8_t base_iv[TOTP_IV_SIZE];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Notification method
|
* @brief Notification method
|
||||||
*/
|
*/
|
||||||
NotificationMethod notification_method;
|
NotificationMethod notification_method;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Main rendering loop mutex
|
|
||||||
*/
|
|
||||||
FuriMutex* mutex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Automation method
|
* @brief Automation method
|
||||||
*/
|
*/
|
||||||
AutomationMethod automation_method;
|
AutomationMethod automation_method;
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
/**
|
||||||
|
* @brief Automation keyboard layout to be used
|
||||||
|
*/
|
||||||
|
AutomationKeyboardLayout automation_kb_layout;
|
||||||
|
|
||||||
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
/**
|
/**
|
||||||
* @brief Bad-Bluetooth worker context
|
* @brief Bad-Bluetooth worker context
|
||||||
*/
|
*/
|
||||||
@@ -110,4 +80,14 @@ typedef struct {
|
|||||||
* @brief Font index to be used to draw TOTP token
|
* @brief Font index to be used to draw TOTP token
|
||||||
*/
|
*/
|
||||||
uint8_t active_font_index;
|
uint8_t active_font_index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Application even queue
|
||||||
|
*/
|
||||||
|
FuriMessageQueue* event_queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crypto settings
|
||||||
|
*/
|
||||||
|
CryptoSettings crypto_settings;
|
||||||
} PluginState;
|
} PluginState;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "token_info.h"
|
#include "token_info.h"
|
||||||
|
#include <furi/core/check.h>
|
||||||
#include <base32.h>
|
#include <base32.h>
|
||||||
#include <base64.h>
|
#include <base64.h>
|
||||||
#include <memset_s.h>
|
#include <memset_s.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "../services/crypto/crypto.h"
|
#include "../services/crypto/crypto_facade.h"
|
||||||
|
|
||||||
TokenInfo* token_info_alloc() {
|
TokenInfo* token_info_alloc() {
|
||||||
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
|
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
|
||||||
@@ -25,7 +26,7 @@ bool token_info_set_secret(
|
|||||||
const char* plain_token_secret,
|
const char* plain_token_secret,
|
||||||
size_t token_secret_length,
|
size_t token_secret_length,
|
||||||
PlainTokenSecretEncoding plain_token_secret_encoding,
|
PlainTokenSecretEncoding plain_token_secret_encoding,
|
||||||
const uint8_t* iv) {
|
const CryptoSettings* crypto_settings) {
|
||||||
if(token_secret_length == 0) return false;
|
if(token_secret_length == 0) return false;
|
||||||
uint8_t* plain_secret;
|
uint8_t* plain_secret;
|
||||||
size_t plain_secret_length;
|
size_t plain_secret_length;
|
||||||
@@ -54,8 +55,8 @@ bool token_info_set_secret(
|
|||||||
free(token_info->token);
|
free(token_info->token);
|
||||||
}
|
}
|
||||||
|
|
||||||
token_info->token =
|
token_info->token = totp_crypto_encrypt(
|
||||||
totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
|
plain_secret, plain_secret_length, crypto_settings, &token_info->token_length);
|
||||||
result = true;
|
result = true;
|
||||||
} else {
|
} else {
|
||||||
result = false;
|
result = false;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <furi/core/string.h>
|
#include <furi/core/string.h>
|
||||||
|
#include "crypto_settings.h"
|
||||||
|
|
||||||
#define TOKEN_HASH_ALGO_SHA1_NAME "sha1"
|
#define TOKEN_HASH_ALGO_SHA1_NAME "sha1"
|
||||||
#define TOKEN_HASH_ALGO_STEAM_NAME "steam"
|
#define TOKEN_HASH_ALGO_STEAM_NAME "steam"
|
||||||
@@ -200,7 +201,7 @@ void token_info_free(TokenInfo* token_info);
|
|||||||
* @param plain_token_secret plain token secret
|
* @param plain_token_secret plain token secret
|
||||||
* @param token_secret_length plain token secret length
|
* @param token_secret_length plain token secret length
|
||||||
* @param plain_token_secret_encoding plain token secret encoding
|
* @param plain_token_secret_encoding plain token secret encoding
|
||||||
* @param iv initialization vecor (IV) to be used for encryption
|
* @param crypto_settings crypto settings
|
||||||
* @return \c true if token successfully set; \c false otherwise
|
* @return \c true if token successfully set; \c false otherwise
|
||||||
*/
|
*/
|
||||||
bool token_info_set_secret(
|
bool token_info_set_secret(
|
||||||
@@ -208,7 +209,7 @@ bool token_info_set_secret(
|
|||||||
const char* plain_token_secret,
|
const char* plain_token_secret,
|
||||||
size_t token_secret_length,
|
size_t token_secret_length,
|
||||||
PlainTokenSecretEncoding plain_token_secret_encoding,
|
PlainTokenSecretEncoding plain_token_secret_encoding,
|
||||||
const uint8_t* iv);
|
const CryptoSettings* crypto_settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets token digits count from \c uint8_t value
|
* @brief Sets token digits count from \c uint8_t value
|
||||||
|
|||||||
@@ -4,6 +4,15 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <font_info.h>
|
#include <font_info.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Draw string using given font
|
||||||
|
* @param canvas canvas to draw string at
|
||||||
|
* @param x horizontal position
|
||||||
|
* @param y vertical position
|
||||||
|
* @param text string to draw
|
||||||
|
* @param text_length string length
|
||||||
|
* @param font font to be used to draw string
|
||||||
|
*/
|
||||||
void canvas_draw_str_ex(
|
void canvas_draw_str_ex(
|
||||||
Canvas* canvas,
|
Canvas* canvas,
|
||||||
uint8_t x,
|
uint8_t x,
|
||||||
|
|||||||
11
applications/external/totp/ui/common_dialogs.h
vendored
11
applications/external/totp/ui/common_dialogs.h
vendored
@@ -3,5 +3,16 @@
|
|||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
#include "../types/plugin_state.h"
|
#include "../types/plugin_state.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shows standard dialog about the fact that error occurred when loading config file
|
||||||
|
* @param plugin_state application state
|
||||||
|
* @return dialog button which user pressed to close the dialog
|
||||||
|
*/
|
||||||
DialogMessageButton totp_dialogs_config_loading_error(PluginState* plugin_state);
|
DialogMessageButton totp_dialogs_config_loading_error(PluginState* plugin_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shows standard dialog about the fact that error occurred when updating config file
|
||||||
|
* @param plugin_state application state
|
||||||
|
* @return dialog button which user pressed to close the dialog
|
||||||
|
*/
|
||||||
DialogMessageButton totp_dialogs_config_updating_error(PluginState* plugin_state);
|
DialogMessageButton totp_dialogs_config_updating_error(PluginState* plugin_state);
|
||||||
@@ -116,3 +116,8 @@ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* con
|
|||||||
|
|
||||||
return processing;
|
return processing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void totp_scene_director_force_redraw(PluginState* const plugin_state) {
|
||||||
|
PluginEvent event = {.type = EventForceRedraw};
|
||||||
|
furi_message_queue_put(plugin_state->event_queue, &event, FuriWaitForever);
|
||||||
|
}
|
||||||
@@ -33,3 +33,9 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_
|
|||||||
* @return \c true if event handled and applilcation should continue; \c false if application should be closed
|
* @return \c true if event handled and applilcation should continue; \c false if application should be closed
|
||||||
*/
|
*/
|
||||||
bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state);
|
bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Forces screen to be redraw\updated
|
||||||
|
* @param plugin_state application state
|
||||||
|
*/
|
||||||
|
void totp_scene_director_force_redraw(PluginState* const plugin_state);
|
||||||
@@ -42,7 +42,7 @@ typedef struct {
|
|||||||
|
|
||||||
struct TotpAddContext {
|
struct TotpAddContext {
|
||||||
SceneState* scene_state;
|
SceneState* scene_state;
|
||||||
uint8_t* iv;
|
const CryptoSettings* crypto_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
|
enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
|
||||||
@@ -58,7 +58,7 @@ static TotpIteratorUpdateTokenResult add_token_handler(TokenInfo* tokenInfo, con
|
|||||||
context_t->scene_state->token_secret,
|
context_t->scene_state->token_secret,
|
||||||
context_t->scene_state->token_secret_length,
|
context_t->scene_state->token_secret_length,
|
||||||
PlainTokenSecretEncodingBase32,
|
PlainTokenSecretEncodingBase32,
|
||||||
context_t->iv)) {
|
context_t->crypto_settings)) {
|
||||||
return TotpIteratorUpdateTokenResultInvalidSecret;
|
return TotpIteratorUpdateTokenResultInvalidSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ bool totp_scene_add_new_token_handle_event(
|
|||||||
break;
|
break;
|
||||||
case ConfirmButton: {
|
case ConfirmButton: {
|
||||||
struct TotpAddContext add_context = {
|
struct TotpAddContext add_context = {
|
||||||
.iv = plugin_state->iv, .scene_state = scene_state};
|
.scene_state = scene_state, .crypto_settings = &plugin_state->crypto_settings};
|
||||||
TokenInfoIteratorContext* iterator_context =
|
TokenInfoIteratorContext* iterator_context =
|
||||||
totp_config_get_token_iterator_context(plugin_state);
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(
|
TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(
|
||||||
|
|||||||
@@ -12,14 +12,30 @@
|
|||||||
#include "../../../services/convert/convert.h"
|
#include "../../../services/convert/convert.h"
|
||||||
#include <roll_value.h>
|
#include <roll_value.h>
|
||||||
#include "../../../features_config.h"
|
#include "../../../features_config.h"
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
|
#define AUTOMATION_LIST_MAX_INDEX (3)
|
||||||
|
#else
|
||||||
|
#define AUTOMATION_LIST_MAX_INDEX (1)
|
||||||
|
#endif
|
||||||
|
#define BAD_KB_LAYOUT_LIST_MAX_INDEX (1)
|
||||||
|
#define FONT_TEST_STR_LENGTH (7)
|
||||||
|
|
||||||
static const char* YES_NO_LIST[] = {"NO", "YES"};
|
static const char* YES_NO_LIST[] = {"NO", "YES"};
|
||||||
static const char* ON_OFF_LIST[] = {"OFF", "ON"};
|
static const char* AUTOMATION_LIST[] = {
|
||||||
|
"None",
|
||||||
|
"USB"
|
||||||
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
|
,
|
||||||
|
"Bluetooth",
|
||||||
|
"BT and USB"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
static const char* BAD_KB_LAYOUT_LIST[] = {"QWERTY", "AZERTY"};
|
||||||
static const char* FONT_TEST_STR = "0123BCD";
|
static const char* FONT_TEST_STR = "0123BCD";
|
||||||
static const uint8_t FONT_TEST_STR_LENGTH = 7;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HoursInput,
|
HoursInput,
|
||||||
@@ -27,10 +43,8 @@ typedef enum {
|
|||||||
FontSelect,
|
FontSelect,
|
||||||
SoundSwitch,
|
SoundSwitch,
|
||||||
VibroSwitch,
|
VibroSwitch,
|
||||||
BadUsbSwitch,
|
AutomationSwitch,
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
BadKeyboardLayoutSelect,
|
||||||
BadBtSwitch,
|
|
||||||
#endif
|
|
||||||
ConfirmButton
|
ConfirmButton
|
||||||
} Control;
|
} Control;
|
||||||
|
|
||||||
@@ -39,11 +53,9 @@ typedef struct {
|
|||||||
uint8_t tz_offset_minutes;
|
uint8_t tz_offset_minutes;
|
||||||
bool notification_sound;
|
bool notification_sound;
|
||||||
bool notification_vibro;
|
bool notification_vibro;
|
||||||
bool badusb_enabled;
|
AutomationMethod automation_method;
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
uint16_t y_offset;
|
||||||
bool badbt_enabled;
|
AutomationKeyboardLayout automation_kb_layout;
|
||||||
#endif
|
|
||||||
uint8_t y_offset;
|
|
||||||
Control selected_control;
|
Control selected_control;
|
||||||
uint8_t active_font;
|
uint8_t active_font;
|
||||||
} SceneState;
|
} SceneState;
|
||||||
@@ -59,10 +71,11 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
|
|||||||
scene_state->tz_offset_minutes = 60.0f * off_dec;
|
scene_state->tz_offset_minutes = 60.0f * off_dec;
|
||||||
scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound;
|
scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound;
|
||||||
scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro;
|
scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro;
|
||||||
scene_state->badusb_enabled = plugin_state->automation_method & AutomationMethodBadUsb;
|
scene_state->automation_method =
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
MIN(plugin_state->automation_method, AUTOMATION_LIST_MAX_INDEX);
|
||||||
scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt;
|
scene_state->automation_kb_layout =
|
||||||
#endif
|
MIN(plugin_state->automation_kb_layout, BAD_KB_LAYOUT_LIST_MAX_INDEX);
|
||||||
|
|
||||||
scene_state->active_font = plugin_state->active_font_index;
|
scene_state->active_font = plugin_state->active_font_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +95,7 @@ static void two_digit_to_str(int8_t num, char* str) {
|
|||||||
|
|
||||||
void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) {
|
void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) {
|
||||||
const SceneState* scene_state = plugin_state->current_scene_state;
|
const SceneState* scene_state = plugin_state->current_scene_state;
|
||||||
|
if(scene_state->selected_control < FontSelect) {
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 0, 0 - scene_state->y_offset, AlignLeft, AlignTop, "Timezone offset");
|
canvas, 0, 0 - scene_state->y_offset, AlignLeft, AlignTop, "Timezone offset");
|
||||||
@@ -90,12 +103,13 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
|
|||||||
|
|
||||||
char tmp_str[4];
|
char tmp_str[4];
|
||||||
two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]);
|
two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]);
|
||||||
canvas_draw_str_aligned(canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:");
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:");
|
||||||
ui_control_select_render(
|
ui_control_select_render(
|
||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
10 - scene_state->y_offset,
|
10 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
&tmp_str[0],
|
&tmp_str[0],
|
||||||
scene_state->selected_control == HoursInput);
|
scene_state->selected_control == HoursInput);
|
||||||
|
|
||||||
@@ -106,18 +120,14 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
|
|||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
28 - scene_state->y_offset,
|
28 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
&tmp_str[0],
|
&tmp_str[0],
|
||||||
scene_state->selected_control == MinutesInput);
|
scene_state->selected_control == MinutesInput);
|
||||||
|
|
||||||
canvas_draw_icon(
|
} else if(scene_state->selected_control < SoundSwitch) {
|
||||||
canvas,
|
|
||||||
SCREEN_WIDTH_CENTER - 5,
|
|
||||||
SCREEN_HEIGHT - 5 - scene_state->y_offset,
|
|
||||||
&I_totp_arrow_bottom_10x5);
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str_aligned(canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Font");
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Font");
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
const FONT_INFO* const font = available_fonts[scene_state->active_font];
|
const FONT_INFO* const font = available_fonts[scene_state->active_font];
|
||||||
@@ -125,7 +135,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
|
|||||||
canvas,
|
canvas,
|
||||||
0,
|
0,
|
||||||
74 - scene_state->y_offset,
|
74 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH,
|
SCREEN_WIDTH - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
font->name,
|
font->name,
|
||||||
scene_state->selected_control == FontSelect);
|
scene_state->selected_control == FontSelect);
|
||||||
|
|
||||||
@@ -136,73 +146,70 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
|
|||||||
canvas_draw_str_ex(
|
canvas_draw_str_ex(
|
||||||
canvas, font_x_offset, font_y_offset, FONT_TEST_STR, FONT_TEST_STR_LENGTH, font);
|
canvas, font_x_offset, font_y_offset, FONT_TEST_STR, FONT_TEST_STR_LENGTH, font);
|
||||||
|
|
||||||
canvas_draw_icon(
|
} else if(scene_state->selected_control < AutomationSwitch) {
|
||||||
canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5);
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications");
|
canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications");
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
canvas_draw_str_aligned(canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:");
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:");
|
||||||
ui_control_select_render(
|
ui_control_select_render(
|
||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
138 - scene_state->y_offset,
|
138 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
YES_NO_LIST[scene_state->notification_sound],
|
YES_NO_LIST[scene_state->notification_sound],
|
||||||
scene_state->selected_control == SoundSwitch);
|
scene_state->selected_control == SoundSwitch);
|
||||||
|
|
||||||
canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:");
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:");
|
||||||
ui_control_select_render(
|
ui_control_select_render(
|
||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
156 - scene_state->y_offset,
|
156 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
YES_NO_LIST[scene_state->notification_vibro],
|
YES_NO_LIST[scene_state->notification_vibro],
|
||||||
scene_state->selected_control == VibroSwitch);
|
scene_state->selected_control == VibroSwitch);
|
||||||
|
} else {
|
||||||
canvas_draw_icon(
|
|
||||||
canvas, SCREEN_WIDTH_CENTER - 5, 187 - scene_state->y_offset, &I_totp_arrow_bottom_10x5);
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation");
|
canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation");
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:");
|
canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "Method:");
|
||||||
ui_control_select_render(
|
ui_control_select_render(
|
||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
202 - scene_state->y_offset,
|
202 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
ON_OFF_LIST[scene_state->badusb_enabled],
|
AUTOMATION_LIST[scene_state->automation_method],
|
||||||
scene_state->selected_control == BadUsbSwitch);
|
scene_state->selected_control == AutomationSwitch);
|
||||||
|
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "Layout:");
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
|
||||||
canvas_draw_str_aligned(canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:");
|
|
||||||
ui_control_select_render(
|
ui_control_select_render(
|
||||||
canvas,
|
canvas,
|
||||||
36,
|
36,
|
||||||
220 - scene_state->y_offset,
|
220 - scene_state->y_offset,
|
||||||
SCREEN_WIDTH - 36,
|
SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
|
||||||
ON_OFF_LIST[scene_state->badbt_enabled],
|
BAD_KB_LAYOUT_LIST[scene_state->automation_kb_layout],
|
||||||
scene_state->selected_control == BadBtSwitch);
|
scene_state->selected_control == BadKeyboardLayoutSelect);
|
||||||
#endif
|
|
||||||
|
|
||||||
ui_control_button_render(
|
ui_control_button_render(
|
||||||
canvas,
|
canvas,
|
||||||
SCREEN_WIDTH_CENTER - 24,
|
SCREEN_WIDTH_CENTER - 24,
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
|
||||||
242 - scene_state->y_offset,
|
242 - scene_state->y_offset,
|
||||||
#else
|
|
||||||
229 - scene_state->y_offset,
|
|
||||||
#endif
|
|
||||||
48,
|
48,
|
||||||
13,
|
13,
|
||||||
"Confirm",
|
"Confirm",
|
||||||
scene_state->selected_control == ConfirmButton);
|
scene_state->selected_control == ConfirmButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_control_vscroll_render(
|
||||||
|
canvas, SCREEN_WIDTH - 3, 0, SCREEN_HEIGHT, scene_state->selected_control, ConfirmButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool totp_scene_app_settings_handle_event(
|
bool totp_scene_app_settings_handle_event(
|
||||||
@@ -267,14 +274,21 @@ bool totp_scene_app_settings_handle_event(
|
|||||||
scene_state->notification_sound = !scene_state->notification_sound;
|
scene_state->notification_sound = !scene_state->notification_sound;
|
||||||
} else if(scene_state->selected_control == VibroSwitch) {
|
} else if(scene_state->selected_control == VibroSwitch) {
|
||||||
scene_state->notification_vibro = !scene_state->notification_vibro;
|
scene_state->notification_vibro = !scene_state->notification_vibro;
|
||||||
} else if(scene_state->selected_control == BadUsbSwitch) {
|
} else if(scene_state->selected_control == AutomationSwitch) {
|
||||||
scene_state->badusb_enabled = !scene_state->badusb_enabled;
|
totp_roll_value_uint8_t(
|
||||||
|
&scene_state->automation_method,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
AUTOMATION_LIST_MAX_INDEX,
|
||||||
|
RollOverflowBehaviorRoll);
|
||||||
|
} else if(scene_state->selected_control == BadKeyboardLayoutSelect) {
|
||||||
|
totp_roll_value_uint8_t(
|
||||||
|
&scene_state->automation_kb_layout,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
BAD_KB_LAYOUT_LIST_MAX_INDEX,
|
||||||
|
RollOverflowBehaviorRoll);
|
||||||
}
|
}
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
|
||||||
else if(scene_state->selected_control == BadBtSwitch) {
|
|
||||||
scene_state->badbt_enabled = !scene_state->badbt_enabled;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case InputKeyLeft:
|
case InputKeyLeft:
|
||||||
if(scene_state->selected_control == HoursInput) {
|
if(scene_state->selected_control == HoursInput) {
|
||||||
@@ -294,14 +308,21 @@ bool totp_scene_app_settings_handle_event(
|
|||||||
scene_state->notification_sound = !scene_state->notification_sound;
|
scene_state->notification_sound = !scene_state->notification_sound;
|
||||||
} else if(scene_state->selected_control == VibroSwitch) {
|
} else if(scene_state->selected_control == VibroSwitch) {
|
||||||
scene_state->notification_vibro = !scene_state->notification_vibro;
|
scene_state->notification_vibro = !scene_state->notification_vibro;
|
||||||
} else if(scene_state->selected_control == BadUsbSwitch) {
|
} else if(scene_state->selected_control == AutomationSwitch) {
|
||||||
scene_state->badusb_enabled = !scene_state->badusb_enabled;
|
totp_roll_value_uint8_t(
|
||||||
|
&scene_state->automation_method,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
AUTOMATION_LIST_MAX_INDEX,
|
||||||
|
RollOverflowBehaviorRoll);
|
||||||
|
} else if(scene_state->selected_control == BadKeyboardLayoutSelect) {
|
||||||
|
totp_roll_value_uint8_t(
|
||||||
|
&scene_state->automation_kb_layout,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
BAD_KB_LAYOUT_LIST_MAX_INDEX,
|
||||||
|
RollOverflowBehaviorRoll);
|
||||||
}
|
}
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
|
||||||
else if(scene_state->selected_control == BadBtSwitch) {
|
|
||||||
scene_state->badbt_enabled = !scene_state->badbt_enabled;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case InputKeyOk:
|
case InputKeyOk:
|
||||||
break;
|
break;
|
||||||
@@ -322,22 +343,18 @@ bool totp_scene_app_settings_handle_event(
|
|||||||
(scene_state->notification_sound ? NotificationMethodSound : NotificationMethodNone) |
|
(scene_state->notification_sound ? NotificationMethodSound : NotificationMethodNone) |
|
||||||
(scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone);
|
(scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone);
|
||||||
|
|
||||||
plugin_state->automation_method = scene_state->badusb_enabled ? AutomationMethodBadUsb :
|
plugin_state->automation_method = scene_state->automation_method;
|
||||||
AutomationMethodNone;
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
|
||||||
plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt :
|
|
||||||
AutomationMethodNone;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
plugin_state->active_font_index = scene_state->active_font;
|
plugin_state->active_font_index = scene_state->active_font;
|
||||||
|
plugin_state->automation_kb_layout = scene_state->automation_kb_layout;
|
||||||
|
|
||||||
if(!totp_config_file_update_user_settings(plugin_state)) {
|
if(!totp_config_file_update_user_settings(plugin_state)) {
|
||||||
totp_dialogs_config_updating_error(plugin_state);
|
totp_dialogs_config_updating_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) {
|
if((scene_state->automation_method & AutomationMethodBadBt) == 0 &&
|
||||||
|
plugin_state->bt_type_code_worker_context != NULL) {
|
||||||
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context);
|
||||||
plugin_state->bt_type_code_worker_context = NULL;
|
plugin_state->bt_type_code_worker_context = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../scene_director.h"
|
#include "../../scene_director.h"
|
||||||
#include "../../totp_scenes_enum.h"
|
#include "../../totp_scenes_enum.h"
|
||||||
#include "../../../services/crypto/crypto.h"
|
#include "../../../services/crypto/crypto_facade.h"
|
||||||
#include "../../../types/user_pin_codes.h"
|
#include "../../../types/user_pin_codes.h"
|
||||||
|
|
||||||
#define MAX_CODE_LENGTH TOTP_IV_SIZE
|
#define MAX_CODE_LENGTH CRYPTO_IV_LENGTH
|
||||||
static const uint8_t PIN_ASTERISK_RADIUS = 3;
|
static const uint8_t PIN_ASTERISK_RADIUS = 3;
|
||||||
static const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
|
static const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ void totp_scene_authenticate_activate(PluginState* plugin_state) {
|
|||||||
scene_state->code_length = 0;
|
scene_state->code_length = 0;
|
||||||
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
||||||
plugin_state->current_scene_state = scene_state;
|
plugin_state->current_scene_state = scene_state;
|
||||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
|
void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||||
@@ -35,7 +35,7 @@ void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_st
|
|||||||
v_shift = -10;
|
v_shift = -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->crypto_verify_data == NULL) {
|
if(plugin_state->crypto_settings.crypto_verify_data == NULL) {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas,
|
canvas,
|
||||||
SCREEN_WIDTH_CENTER,
|
SCREEN_WIDTH_CENTER,
|
||||||
@@ -123,20 +123,22 @@ bool totp_scene_authenticate_handle_event(
|
|||||||
}
|
}
|
||||||
} else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) {
|
} else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) {
|
||||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
|
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
|
||||||
plugin_state, &scene_state->code_input[0], scene_state->code_length);
|
&plugin_state->crypto_settings, &scene_state->code_input[0], scene_state->code_length);
|
||||||
|
|
||||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||||
totp_config_file_update_crypto_signatures(plugin_state);
|
totp_config_file_update_crypto_signatures(plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(totp_crypto_verify_key(plugin_state)) {
|
if(totp_crypto_verify_key(&plugin_state->crypto_settings)) {
|
||||||
FURI_LOG_D(LOGGING_TAG, "PIN is valid");
|
FURI_LOG_D(LOGGING_TAG, "PIN is valid");
|
||||||
|
totp_config_file_ensure_latest_encryption(
|
||||||
|
plugin_state, &scene_state->code_input[0], scene_state->code_length);
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
|
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
|
||||||
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
||||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
|
||||||
scene_state->code_length = 0;
|
scene_state->code_length = 0;
|
||||||
|
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "../../../features_config.h"
|
#include "../../../features_config.h"
|
||||||
#include "../../../workers/generate_totp_code/generate_totp_code.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_AUTOMATION_ENABLED
|
||||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -33,50 +33,40 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char last_code[TokenDigitsCountMax + 1];
|
char last_code[TokenDigitsCountMax + 1];
|
||||||
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
||||||
NotificationMessage const** notification_sequence_new_token;
|
NotificationMessage const* notification_sequence_new_token[8];
|
||||||
NotificationMessage const** notification_sequence_automation;
|
NotificationMessage const* notification_sequence_automation[11];
|
||||||
FuriMutex* last_code_update_sync;
|
FuriMutex* last_code_update_sync;
|
||||||
TotpGenerateCodeWorkerContext* generate_code_worker_context;
|
TotpGenerateCodeWorkerContext* generate_code_worker_context;
|
||||||
UiPrecalculatedDimensions ui_precalculated_dimensions;
|
UiPrecalculatedDimensions ui_precalculated_dimensions;
|
||||||
const FONT_INFO* active_font;
|
const FONT_INFO* active_font;
|
||||||
|
NotificationApp* notification_app;
|
||||||
} SceneState;
|
} SceneState;
|
||||||
|
|
||||||
static const NotificationSequence*
|
static const NotificationSequence*
|
||||||
get_notification_sequence_new_token(const PluginState* plugin_state, SceneState* scene_state) {
|
get_notification_sequence_new_token(const PluginState* plugin_state, SceneState* scene_state) {
|
||||||
if(scene_state->notification_sequence_new_token == NULL) {
|
if(scene_state->notification_sequence_new_token[0] == NULL) {
|
||||||
uint8_t i = 0;
|
NotificationMessage const** sequence = &scene_state->notification_sequence_new_token[0];
|
||||||
uint8_t length = 4;
|
*(sequence++) = &message_display_backlight_on;
|
||||||
|
*(sequence++) = &message_green_255;
|
||||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||||
length += 2;
|
*(sequence++) = &message_vibro_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||||
length += 2;
|
*(sequence++) = &message_note_c5;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state->notification_sequence_new_token = malloc(sizeof(void*) * length);
|
*(sequence++) = &message_delay_50;
|
||||||
furi_check(scene_state->notification_sequence_new_token != NULL);
|
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_display_backlight_on;
|
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_green_255;
|
|
||||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_vibro_on;
|
*(sequence++) = &message_vibro_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_note_c5;
|
*(sequence++) = &message_sound_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_delay_50;
|
*(sequence++) = NULL;
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_vibro_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
|
||||||
scene_state->notification_sequence_new_token[i++] = &message_sound_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_state->notification_sequence_new_token[i++] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (NotificationSequence*)scene_state->notification_sequence_new_token;
|
return (NotificationSequence*)scene_state->notification_sequence_new_token;
|
||||||
@@ -84,44 +74,33 @@ 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_automation == NULL) {
|
if(scene_state->notification_sequence_automation[0] == NULL) {
|
||||||
uint8_t i = 0;
|
NotificationMessage const** sequence = &scene_state->notification_sequence_automation[0];
|
||||||
uint8_t length = 3;
|
|
||||||
|
*(sequence++) = &message_blue_255;
|
||||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||||
length += 2;
|
*(sequence++) = &message_vibro_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||||
length += 6;
|
*(sequence++) = &message_note_d5; //-V525
|
||||||
|
*(sequence++) = &message_delay_50;
|
||||||
|
*(sequence++) = &message_note_e4;
|
||||||
|
*(sequence++) = &message_delay_50;
|
||||||
|
*(sequence++) = &message_note_f3;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state->notification_sequence_automation = malloc(sizeof(void*) * length);
|
*(sequence++) = &message_delay_50;
|
||||||
furi_check(scene_state->notification_sequence_automation != NULL);
|
|
||||||
|
|
||||||
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_automation[i++] = &message_vibro_on;
|
*(sequence++) = &message_vibro_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||||
scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525
|
*(sequence++) = &message_sound_off;
|
||||||
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_automation[i++] = &message_delay_50;
|
*(sequence++) = NULL;
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
|
||||||
scene_state->notification_sequence_automation[i++] = &message_vibro_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
|
||||||
scene_state->notification_sequence_automation[i++] = &message_sound_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_state->notification_sequence_automation[i++] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
||||||
@@ -153,7 +132,7 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void on_new_token_code_generated(bool time_left, void* context) {
|
static void on_new_token_code_generated(bool time_left, void* context) {
|
||||||
const PluginState* plugin_state = context;
|
PluginState* const plugin_state = context;
|
||||||
const TokenInfoIteratorContext* iterator_context =
|
const TokenInfoIteratorContext* iterator_context =
|
||||||
totp_config_get_token_iterator_context(plugin_state);
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||||
@@ -174,13 +153,16 @@ static void on_new_token_code_generated(bool time_left, void* context) {
|
|||||||
|
|
||||||
if(time_left) {
|
if(time_left) {
|
||||||
notification_message(
|
notification_message(
|
||||||
plugin_state->notification_app,
|
scene_state->notification_app,
|
||||||
get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state));
|
get_notification_sequence_new_token(plugin_state, scene_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totp_scene_director_force_redraw(plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) {
|
static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) {
|
||||||
SceneState* scene_state = context;
|
PluginState* const plugin_state = context;
|
||||||
|
SceneState* scene_state = plugin_state->current_scene_state;
|
||||||
scene_state->ui_precalculated_dimensions.progress_bar_width =
|
scene_state->ui_precalculated_dimensions.progress_bar_width =
|
||||||
(uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
|
(uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
|
||||||
scene_state->ui_precalculated_dimensions.progress_bar_x =
|
scene_state->ui_precalculated_dimensions.progress_bar_x =
|
||||||
@@ -188,6 +170,7 @@ static void on_code_lifetime_updated_generated(float code_lifetime_percent, void
|
|||||||
scene_state->ui_precalculated_dimensions.progress_bar_width) >>
|
scene_state->ui_precalculated_dimensions.progress_bar_width) >>
|
||||||
1) +
|
1) +
|
||||||
PROGRESS_BAR_MARGIN;
|
PROGRESS_BAR_MARGIN;
|
||||||
|
totp_scene_director_force_redraw(plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
||||||
@@ -200,12 +183,18 @@ void totp_scene_generate_token_activate(PluginState* 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, TokenDigitsCountMax + 1, scene_state->last_code_update_sync);
|
scene_state->last_code,
|
||||||
|
TokenDigitsCountMax + 1,
|
||||||
|
scene_state->last_code_update_sync,
|
||||||
|
plugin_state->automation_kb_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state->active_font = available_fonts[plugin_state->active_font_index];
|
scene_state->active_font = available_fonts[plugin_state->active_font_index];
|
||||||
|
scene_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
scene_state->notification_sequence_automation[0] = NULL;
|
||||||
|
scene_state->notification_sequence_new_token[0] = NULL;
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
|
|
||||||
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
||||||
if(plugin_state->bt_type_code_worker_context == NULL) {
|
if(plugin_state->bt_type_code_worker_context == NULL) {
|
||||||
@@ -215,7 +204,8 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
|||||||
plugin_state->bt_type_code_worker_context,
|
plugin_state->bt_type_code_worker_context,
|
||||||
scene_state->last_code,
|
scene_state->last_code,
|
||||||
TokenDigitsCountMax + 1,
|
TokenDigitsCountMax + 1,
|
||||||
scene_state->last_code_update_sync);
|
scene_state->last_code_update_sync,
|
||||||
|
plugin_state->automation_kb_layout);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
const TokenInfoIteratorContext* iterator_context =
|
const TokenInfoIteratorContext* iterator_context =
|
||||||
@@ -225,7 +215,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
|||||||
totp_token_info_iterator_get_current_token(iterator_context),
|
totp_token_info_iterator_get_current_token(iterator_context),
|
||||||
scene_state->last_code_update_sync,
|
scene_state->last_code_update_sync,
|
||||||
plugin_state->timezone_offset,
|
plugin_state->timezone_offset,
|
||||||
plugin_state->iv);
|
&plugin_state->crypto_settings);
|
||||||
|
|
||||||
totp_generate_code_worker_set_code_generated_handler(
|
totp_generate_code_worker_set_code_generated_handler(
|
||||||
scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
|
scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
|
||||||
@@ -233,7 +223,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
|||||||
totp_generate_code_worker_set_lifetime_changed_handler(
|
totp_generate_code_worker_set_lifetime_changed_handler(
|
||||||
scene_state->generate_code_worker_context,
|
scene_state->generate_code_worker_context,
|
||||||
&on_code_lifetime_updated_generated,
|
&on_code_lifetime_updated_generated,
|
||||||
scene_state);
|
plugin_state);
|
||||||
|
|
||||||
update_totp_params(
|
update_totp_params(
|
||||||
plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context));
|
plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context));
|
||||||
@@ -297,11 +287,10 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
|||||||
canvas, SCREEN_WIDTH - 8, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9);
|
canvas, SCREEN_WIDTH - 8, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_AUTOMATION_ICONS_ENABLED
|
|
||||||
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||||
canvas_draw_icon(
|
canvas_draw_icon(
|
||||||
canvas,
|
canvas,
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
SCREEN_WIDTH_CENTER -
|
SCREEN_WIDTH_CENTER -
|
||||||
(plugin_state->automation_method & AutomationMethodBadBt ? 33 : 15),
|
(plugin_state->automation_method & AutomationMethodBadBt ? 33 : 15),
|
||||||
#else
|
#else
|
||||||
@@ -312,7 +301,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
|||||||
&I_hid_usb_31x9);
|
&I_hid_usb_31x9);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(plugin_state->automation_method & AutomationMethodBadBt &&
|
if(plugin_state->automation_method & AutomationMethodBadBt &&
|
||||||
plugin_state->bt_type_code_worker_context != NULL &&
|
plugin_state->bt_type_code_worker_context != NULL &&
|
||||||
totp_bt_type_code_worker_is_advertising(plugin_state->bt_type_code_worker_context)) {
|
totp_bt_type_code_worker_is_advertising(plugin_state->bt_type_code_worker_context)) {
|
||||||
@@ -324,7 +313,6 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
|||||||
&I_hid_ble_31x9);
|
&I_hid_ble_31x9);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool totp_scene_generate_token_handle_event(
|
bool totp_scene_generate_token_handle_event(
|
||||||
@@ -350,11 +338,11 @@ bool totp_scene_generate_token_handle_event(
|
|||||||
TotpUsbTypeCodeWorkerEventType,
|
TotpUsbTypeCodeWorkerEventType,
|
||||||
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||||
notification_message(
|
notification_message(
|
||||||
plugin_state->notification_app,
|
scene_state->notification_app,
|
||||||
get_notification_sequence_automation(plugin_state, scene_state));
|
get_notification_sequence_automation(plugin_state, scene_state));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
else if(
|
else if(
|
||||||
event->input.key == InputKeyUp &&
|
event->input.key == InputKeyUp &&
|
||||||
plugin_state->automation_method & AutomationMethodBadBt) {
|
plugin_state->automation_method & AutomationMethodBadBt) {
|
||||||
@@ -366,7 +354,7 @@ bool totp_scene_generate_token_handle_event(
|
|||||||
TotpBtTypeCodeWorkerEventType,
|
TotpBtTypeCodeWorkerEventType,
|
||||||
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||||
notification_message(
|
notification_message(
|
||||||
plugin_state->notification_app,
|
scene_state->notification_app,
|
||||||
get_notification_sequence_automation(plugin_state, scene_state));
|
get_notification_sequence_automation(plugin_state, scene_state));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -427,23 +415,17 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
|||||||
|
|
||||||
totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
|
totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
|
||||||
|
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_AUTOMATION_ENABLED
|
||||||
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
||||||
totp_bt_type_code_worker_stop(plugin_state->bt_type_code_worker_context);
|
totp_bt_type_code_worker_stop(plugin_state->bt_type_code_worker_context);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(scene_state->notification_sequence_new_token != NULL) {
|
|
||||||
free(scene_state->notification_sequence_new_token);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
free(scene_state);
|
free(scene_state);
|
||||||
|
|||||||
24
applications/external/totp/ui/ui_controls.c
vendored
24
applications/external/totp/ui/ui_controls.c
vendored
@@ -112,3 +112,27 @@ void ui_control_button_render(
|
|||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ui_control_vscroll_render(
|
||||||
|
Canvas* const canvas,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t height,
|
||||||
|
uint8_t position,
|
||||||
|
uint8_t max_position) {
|
||||||
|
canvas_draw_line(canvas, x, y, x, y + height);
|
||||||
|
uint8_t block_height = height / MIN(10, max_position);
|
||||||
|
uint8_t block_position_y =
|
||||||
|
height * ((float)position / (float)max_position) - (block_height >> 1);
|
||||||
|
uint8_t block_position_y_abs = y + block_position_y;
|
||||||
|
if(block_position_y_abs + block_height > height) {
|
||||||
|
block_position_y_abs = height - block_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_box(
|
||||||
|
canvas,
|
||||||
|
x - (UI_CONTROL_VSCROLL_WIDTH >> 1),
|
||||||
|
block_position_y_abs,
|
||||||
|
UI_CONTROL_VSCROLL_WIDTH,
|
||||||
|
block_height);
|
||||||
|
}
|
||||||
|
|||||||
19
applications/external/totp/ui/ui_controls.h
vendored
19
applications/external/totp/ui/ui_controls.h
vendored
@@ -3,6 +3,8 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
|
|
||||||
|
#define UI_CONTROL_VSCROLL_WIDTH (3)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Renders TextBox control
|
* @brief Renders TextBox control
|
||||||
* @param canvas canvas to render control at
|
* @param canvas canvas to render control at
|
||||||
@@ -51,3 +53,20 @@ void ui_control_select_render(
|
|||||||
uint8_t width,
|
uint8_t width,
|
||||||
const char* text,
|
const char* text,
|
||||||
bool is_selected);
|
bool is_selected);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Renders vertical scroll bar
|
||||||
|
* @param canvas canvas to render control at
|
||||||
|
* @param x horizontal position of a control to be rendered at
|
||||||
|
* @param y vertical position of a control to be rendered at
|
||||||
|
* @param height control height
|
||||||
|
* @param position current position
|
||||||
|
* @param max_position maximal position
|
||||||
|
*/
|
||||||
|
void ui_control_vscroll_render(
|
||||||
|
Canvas* const canvas,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t height,
|
||||||
|
uint8_t position,
|
||||||
|
uint8_t max_position);
|
||||||
|
|||||||
5
applications/external/totp/version.h
vendored
Normal file
5
applications/external/totp/version.h
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TOTP_APP_VERSION_MAJOR (3)
|
||||||
|
#define TOTP_APP_VERSION_MINOR (2)
|
||||||
|
#define TOTP_APP_VERSION_PATCH (0)
|
||||||
@@ -12,13 +12,14 @@
|
|||||||
#include "../../types/token_info.h"
|
#include "../../types/token_info.h"
|
||||||
#include "../type_code_common.h"
|
#include "../type_code_common.h"
|
||||||
#include "../../features_config.h"
|
#include "../../features_config.h"
|
||||||
|
#include "../../services/config/constants.h"
|
||||||
|
|
||||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME_UL
|
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME_UL
|
||||||
#define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH
|
#define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH
|
||||||
#define TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE
|
#define TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
|
#define HID_BT_KEYS_STORAGE_PATH CONFIG_FILE_DIRECTORY_PATH "/.bt_hid.keys"
|
||||||
|
|
||||||
struct TotpBtTypeCodeWorkerContext {
|
struct TotpBtTypeCodeWorkerContext {
|
||||||
char* code_buffer;
|
char* code_buffer;
|
||||||
@@ -33,6 +34,7 @@ struct TotpBtTypeCodeWorkerContext {
|
|||||||
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
|
||||||
|
AutomationKeyboardLayout keyboard_layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool totp_type_code_worker_stop_requested() {
|
static inline bool totp_type_code_worker_stop_requested() {
|
||||||
@@ -73,7 +75,8 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
|
|||||||
&furi_hal_bt_hid_kb_release,
|
&furi_hal_bt_hid_kb_release,
|
||||||
context->code_buffer,
|
context->code_buffer,
|
||||||
context->code_buffer_size,
|
context->code_buffer_size,
|
||||||
context->flags);
|
context->flags,
|
||||||
|
context->keyboard_layout);
|
||||||
furi_mutex_release(context->code_buffer_sync);
|
furi_mutex_release(context->code_buffer_sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,11 +122,13 @@ void totp_bt_type_code_worker_start(
|
|||||||
TotpBtTypeCodeWorkerContext* context,
|
TotpBtTypeCodeWorkerContext* context,
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync) {
|
FuriMutex* code_buffer_sync,
|
||||||
|
AutomationKeyboardLayout keyboard_layout) {
|
||||||
furi_check(context != NULL);
|
furi_check(context != NULL);
|
||||||
context->code_buffer = code_buffer;
|
context->code_buffer = code_buffer;
|
||||||
context->code_buffer_size = code_buffer_size;
|
context->code_buffer_size = code_buffer_size;
|
||||||
context->code_buffer_sync = code_buffer_sync;
|
context->code_buffer_sync = code_buffer_sync;
|
||||||
|
context->keyboard_layout = keyboard_layout;
|
||||||
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);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <furi/core/mutex.h>
|
#include <furi/core/mutex.h>
|
||||||
|
#include "../../types/automation_kb_layout.h"
|
||||||
|
|
||||||
typedef uint8_t TotpBtTypeCodeWorkerEvent;
|
typedef uint8_t TotpBtTypeCodeWorkerEvent;
|
||||||
|
|
||||||
@@ -47,12 +48,14 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
|
|||||||
* @param code_buffer code buffer to be used to automate
|
* @param code_buffer code buffer to be used to automate
|
||||||
* @param code_buffer_size code buffer size
|
* @param code_buffer_size code buffer size
|
||||||
* @param code_buffer_sync code buffer synchronization primitive
|
* @param code_buffer_sync code buffer synchronization primitive
|
||||||
|
* @param keyboard_layout keyboard layout to be used
|
||||||
*/
|
*/
|
||||||
void totp_bt_type_code_worker_start(
|
void totp_bt_type_code_worker_start(
|
||||||
TotpBtTypeCodeWorkerContext* context,
|
TotpBtTypeCodeWorkerContext* context,
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync);
|
FuriMutex* code_buffer_sync,
|
||||||
|
AutomationKeyboardLayout keyboard_layout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops bluetooth token input automation worker
|
* @brief Stops bluetooth token input automation worker
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "generate_totp_code.h"
|
#include "generate_totp_code.h"
|
||||||
#include <furi/core/thread.h>
|
#include <furi/core/thread.h>
|
||||||
#include "../../services/crypto/crypto.h"
|
#include <furi/core/check.h>
|
||||||
|
#include "../../services/crypto/crypto_facade.h"
|
||||||
#include "../../services/totp/totp.h"
|
#include "../../services/totp/totp.h"
|
||||||
#include "../../services/convert/convert.h"
|
#include "../../services/convert/convert.h"
|
||||||
#include <furi_hal_rtc.h>
|
#include <furi_hal_rtc.h>
|
||||||
@@ -14,7 +15,7 @@ struct TotpGenerateCodeWorkerContext {
|
|||||||
FuriMutex* code_buffer_sync;
|
FuriMutex* code_buffer_sync;
|
||||||
const TokenInfo* token_info;
|
const TokenInfo* token_info;
|
||||||
float timezone_offset;
|
float timezone_offset;
|
||||||
uint8_t* iv;
|
const CryptoSettings* crypto_settings;
|
||||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
||||||
void* on_new_code_generated_handler_context;
|
void* on_new_code_generated_handler_context;
|
||||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
||||||
@@ -69,7 +70,7 @@ static void generate_totp_code(
|
|||||||
if(token_info->token != NULL && token_info->token_length > 0) {
|
if(token_info->token != NULL && token_info->token_length > 0) {
|
||||||
size_t key_length;
|
size_t key_length;
|
||||||
uint8_t* key = totp_crypto_decrypt(
|
uint8_t* key = totp_crypto_decrypt(
|
||||||
token_info->token, token_info->token_length, context->iv, &key_length);
|
token_info->token, token_info->token_length, context->crypto_settings, &key_length);
|
||||||
|
|
||||||
int_token_to_str(
|
int_token_to_str(
|
||||||
totp_at(
|
totp_at(
|
||||||
@@ -147,14 +148,14 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
|||||||
const TokenInfo* token_info,
|
const TokenInfo* token_info,
|
||||||
FuriMutex* code_buffer_sync,
|
FuriMutex* code_buffer_sync,
|
||||||
float timezone_offset,
|
float timezone_offset,
|
||||||
uint8_t* iv) {
|
const CryptoSettings* crypto_settings) {
|
||||||
TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
|
TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
|
||||||
furi_check(context != NULL);
|
furi_check(context != NULL);
|
||||||
context->code_buffer = code_buffer;
|
context->code_buffer = code_buffer;
|
||||||
context->token_info = token_info;
|
context->token_info = token_info;
|
||||||
context->code_buffer_sync = code_buffer_sync;
|
context->code_buffer_sync = code_buffer_sync;
|
||||||
context->timezone_offset = timezone_offset;
|
context->timezone_offset = timezone_offset;
|
||||||
context->iv = iv;
|
context->crypto_settings = crypto_settings;
|
||||||
context->thread = furi_thread_alloc();
|
context->thread = furi_thread_alloc();
|
||||||
furi_thread_set_name(context->thread, "TOTPGenerateWorker");
|
furi_thread_set_name(context->thread, "TOTPGenerateWorker");
|
||||||
furi_thread_set_stack_size(context->thread, 2048);
|
furi_thread_set_stack_size(context->thread, 2048);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ enum TotGenerateCodeWorkerEvents {
|
|||||||
* @param token_info token info to be used to generate code
|
* @param token_info token info to be used to generate code
|
||||||
* @param code_buffer_sync code buffer synchronization primitive
|
* @param code_buffer_sync code buffer synchronization primitive
|
||||||
* @param timezone_offset timezone offset to be used to generate code
|
* @param timezone_offset timezone offset to be used to generate code
|
||||||
* @param iv initialization vector (IV) to be used to decrypt token secret
|
* @param crypto_settings crypto settings
|
||||||
* @return worker context
|
* @return worker context
|
||||||
*/
|
*/
|
||||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||||
@@ -46,7 +46,7 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
|||||||
const TokenInfo* token_info,
|
const TokenInfo* token_info,
|
||||||
FuriMutex* code_buffer_sync,
|
FuriMutex* code_buffer_sync,
|
||||||
float timezone_offset,
|
float timezone_offset,
|
||||||
uint8_t* iv);
|
const CryptoSettings* crypto_settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops generate code worker
|
* @brief Stops generate code worker
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
#include <furi/core/kernel.h>
|
#include <furi/core/kernel.h>
|
||||||
#include "../../services/convert/convert.h"
|
#include "../../services/convert/convert.h"
|
||||||
|
|
||||||
static const uint8_t hid_number_keys[] = {
|
#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_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_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_A, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E,
|
||||||
@@ -13,6 +15,16 @@ static const uint8_t hid_number_keys[] = {
|
|||||||
HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Y,
|
HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Y,
|
||||||
HID_KEYBOARD_Z};
|
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 uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
||||||
if(features & TokenAutomationFeatureTypeSlower) {
|
if(features & TokenAutomationFeatureTypeSlower) {
|
||||||
return 100;
|
return 100;
|
||||||
@@ -44,21 +56,38 @@ void totp_type_code_worker_execute_automation(
|
|||||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||||
const char* code_buffer,
|
const char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
TokenAutomationFeature features) {
|
TokenAutomationFeature features,
|
||||||
|
AutomationKeyboardLayout keyboard_layout) {
|
||||||
furi_delay_ms(500);
|
furi_delay_ms(500);
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
char cb_char;
|
char cb_char;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while(i < code_buffer_size && (cb_char = code_buffer[i]) != 0) {
|
while(i < code_buffer_size && (cb_char = code_buffer[i]) != 0) {
|
||||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(cb_char);
|
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(cb_char);
|
||||||
if(char_index > 9) {
|
if(char_index > 9) {
|
||||||
char_index = cb_char - 'A' + 10;
|
char_index = cb_char - 'A' + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(char_index >= sizeof(hid_number_keys)) break;
|
if(char_index >= HID_KEYS_MAP_LENGTH) break;
|
||||||
|
|
||||||
uint16_t hid_kb_key = hid_number_keys[char_index];
|
uint16_t hid_kb_key = keyboard_layout_dict[char_index];
|
||||||
if(char_index > 9) {
|
|
||||||
|
// 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;
|
hid_kb_key |= KEY_MOD_LEFT_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../types/token_info.h"
|
#include "../types/token_info.h"
|
||||||
|
#include "../types/automation_kb_layout.h"
|
||||||
|
|
||||||
typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
||||||
|
|
||||||
@@ -11,10 +12,12 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
|||||||
* @param code_buffer code buffer to be typed
|
* @param code_buffer code buffer to be typed
|
||||||
* @param code_buffer_size code buffer size
|
* @param code_buffer_size code buffer size
|
||||||
* @param features automation features
|
* @param features automation features
|
||||||
|
* @param keyboard_layout keyboard layout to be used
|
||||||
*/
|
*/
|
||||||
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* code_buffer,
|
const char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
TokenAutomationFeature features);
|
TokenAutomationFeature features,
|
||||||
|
AutomationKeyboardLayout keyboard_layout);
|
||||||
@@ -15,6 +15,7 @@ struct TotpUsbTypeCodeWorkerContext {
|
|||||||
FuriThread* thread;
|
FuriThread* thread;
|
||||||
FuriMutex* code_buffer_sync;
|
FuriMutex* code_buffer_sync;
|
||||||
FuriHalUsbInterface* usb_mode_prev;
|
FuriHalUsbInterface* usb_mode_prev;
|
||||||
|
AutomationKeyboardLayout keyboard_layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
||||||
@@ -45,7 +46,8 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
|
|||||||
&furi_hal_hid_kb_release,
|
&furi_hal_hid_kb_release,
|
||||||
context->code_buffer,
|
context->code_buffer,
|
||||||
context->code_buffer_size,
|
context->code_buffer_size,
|
||||||
context->flags);
|
context->flags,
|
||||||
|
context->keyboard_layout);
|
||||||
furi_mutex_release(context->code_buffer_sync);
|
furi_mutex_release(context->code_buffer_sync);
|
||||||
|
|
||||||
furi_delay_ms(100);
|
furi_delay_ms(100);
|
||||||
@@ -83,7 +85,8 @@ 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_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync) {
|
FuriMutex* code_buffer_sync,
|
||||||
|
AutomationKeyboardLayout keyboard_layout) {
|
||||||
TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
|
TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
|
||||||
furi_check(context != NULL);
|
furi_check(context != NULL);
|
||||||
context->code_buffer = code_buffer;
|
context->code_buffer = code_buffer;
|
||||||
@@ -91,6 +94,7 @@ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
|||||||
context->code_buffer_sync = code_buffer_sync;
|
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;
|
||||||
|
context->keyboard_layout = keyboard_layout;
|
||||||
furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
|
furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
|
||||||
furi_thread_set_stack_size(context->thread, 1024);
|
furi_thread_set_stack_size(context->thread, 1024);
|
||||||
furi_thread_set_context(context->thread, context);
|
furi_thread_set_context(context->thread, context);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <furi/core/mutex.h>
|
#include <furi/core/mutex.h>
|
||||||
|
#include "../../types/automation_kb_layout.h"
|
||||||
|
|
||||||
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
||||||
|
|
||||||
@@ -34,12 +35,14 @@ enum TotpUsbTypeCodeWorkerEvents {
|
|||||||
* @param code_buffer code buffer to be used to automate
|
* @param code_buffer code buffer to be used to automate
|
||||||
* @param code_buffer_size code buffer size
|
* @param code_buffer_size code buffer size
|
||||||
* @param code_buffer_sync code buffer synchronization primitive
|
* @param code_buffer_sync code buffer synchronization primitive
|
||||||
|
* @param keyboard_layout keyboard layout to be used
|
||||||
* @return worker context
|
* @return worker context
|
||||||
*/
|
*/
|
||||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync);
|
FuriMutex* code_buffer_sync,
|
||||||
|
AutomationKeyboardLayout keyboard_layout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops USB token input automation worker
|
* @brief Stops USB token input automation worker
|
||||||
|
|||||||
@@ -171,6 +171,10 @@ static Infrared* infrared_alloc() {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
view_dispatcher, InfraredViewStack, view_stack_get_view(infrared->view_stack));
|
view_dispatcher, InfraredViewStack, view_stack_get_view(infrared->view_stack));
|
||||||
|
|
||||||
|
infrared->move_view = infrared_move_view_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
view_dispatcher, InfraredViewMove, infrared_move_view_get_view(infrared->move_view));
|
||||||
|
|
||||||
if(app_state->is_debug_enabled) {
|
if(app_state->is_debug_enabled) {
|
||||||
infrared->debug_view = infrared_debug_view_alloc();
|
infrared->debug_view = infrared_debug_view_alloc();
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
@@ -218,6 +222,9 @@ static void infrared_free(Infrared* infrared) {
|
|||||||
view_dispatcher_remove_view(view_dispatcher, InfraredViewStack);
|
view_dispatcher_remove_view(view_dispatcher, InfraredViewStack);
|
||||||
view_stack_free(infrared->view_stack);
|
view_stack_free(infrared->view_stack);
|
||||||
|
|
||||||
|
view_dispatcher_remove_view(view_dispatcher, InfraredViewMove);
|
||||||
|
infrared_move_view_free(infrared->move_view);
|
||||||
|
|
||||||
if(app_state->is_debug_enabled) {
|
if(app_state->is_debug_enabled) {
|
||||||
view_dispatcher_remove_view(view_dispatcher, InfraredViewDebugView);
|
view_dispatcher_remove_view(view_dispatcher, InfraredViewDebugView);
|
||||||
infrared_debug_view_free(infrared->debug_view);
|
infrared_debug_view_free(infrared->debug_view);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "scenes/infrared_scene.h"
|
#include "scenes/infrared_scene.h"
|
||||||
#include "views/infrared_progress_view.h"
|
#include "views/infrared_progress_view.h"
|
||||||
#include "views/infrared_debug_view.h"
|
#include "views/infrared_debug_view.h"
|
||||||
|
#include "views/infrared_move_view.h"
|
||||||
|
|
||||||
#include "rpc/rpc_app.h"
|
#include "rpc/rpc_app.h"
|
||||||
|
|
||||||
@@ -61,8 +62,6 @@ typedef enum {
|
|||||||
InfraredEditModeNone,
|
InfraredEditModeNone,
|
||||||
InfraredEditModeRename,
|
InfraredEditModeRename,
|
||||||
InfraredEditModeDelete,
|
InfraredEditModeDelete,
|
||||||
InfraredEditModeMove,
|
|
||||||
InfraredEditModeMoveSelectDest
|
|
||||||
} InfraredEditMode;
|
} InfraredEditMode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -98,6 +97,7 @@ struct Infrared {
|
|||||||
|
|
||||||
ViewStack* view_stack;
|
ViewStack* view_stack;
|
||||||
InfraredDebugView* debug_view;
|
InfraredDebugView* debug_view;
|
||||||
|
InfraredMoveView* move_view;
|
||||||
|
|
||||||
ButtonPanel* button_panel;
|
ButtonPanel* button_panel;
|
||||||
Loading* loading;
|
Loading* loading;
|
||||||
@@ -119,6 +119,7 @@ typedef enum {
|
|||||||
InfraredViewPopup,
|
InfraredViewPopup,
|
||||||
InfraredViewStack,
|
InfraredViewStack,
|
||||||
InfraredViewDebugView,
|
InfraredViewDebugView,
|
||||||
|
InfraredViewMove,
|
||||||
} InfraredView;
|
} InfraredView;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -108,19 +108,13 @@ bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) {
|
|||||||
return infrared_remote_store(remote);
|
return infrared_remote_store(remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest) {
|
void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest) {
|
||||||
furi_assert(index_orig < InfraredButtonArray_size(remote->buttons));
|
furi_assert(index_orig < InfraredButtonArray_size(remote->buttons));
|
||||||
furi_assert(index_dest <= InfraredButtonArray_size(remote->buttons));
|
furi_assert(index_dest < InfraredButtonArray_size(remote->buttons));
|
||||||
if(index_orig == index_dest) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
InfraredRemoteButton* button;
|
InfraredRemoteButton* button;
|
||||||
InfraredButtonArray_pop_at(&button, remote->buttons, index_orig);
|
InfraredButtonArray_pop_at(&button, remote->buttons, index_orig);
|
||||||
if(index_orig > index_dest)
|
|
||||||
InfraredButtonArray_push_at(remote->buttons, index_dest, button);
|
InfraredButtonArray_push_at(remote->buttons, index_dest, button);
|
||||||
else
|
|
||||||
InfraredButtonArray_push_at(remote->buttons, index_dest - 1, button);
|
|
||||||
return infrared_remote_store(remote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool infrared_remote_store(InfraredRemote* remote) {
|
bool infrared_remote_store(InfraredRemote* remote) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* nam
|
|||||||
bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal);
|
bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal);
|
||||||
bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index);
|
bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index);
|
||||||
bool infrared_remote_delete_button(InfraredRemote* remote, size_t index);
|
bool infrared_remote_delete_button(InfraredRemote* remote, size_t index);
|
||||||
bool infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest);
|
void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest);
|
||||||
|
|
||||||
bool infrared_remote_store(InfraredRemote* remote);
|
bool infrared_remote_store(InfraredRemote* remote);
|
||||||
bool infrared_remote_load(InfraredRemote* remote, FuriString* path);
|
bool infrared_remote_load(InfraredRemote* remote, FuriString* path);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ ADD_SCENE(infrared, edit_button_select, EditButtonSelect)
|
|||||||
ADD_SCENE(infrared, edit_rename, EditRename)
|
ADD_SCENE(infrared, edit_rename, EditRename)
|
||||||
ADD_SCENE(infrared, edit_rename_done, EditRenameDone)
|
ADD_SCENE(infrared, edit_rename_done, EditRenameDone)
|
||||||
ADD_SCENE(infrared, edit_move, EditMove)
|
ADD_SCENE(infrared, edit_move, EditMove)
|
||||||
ADD_SCENE(infrared, edit_move_done, EditMoveDone)
|
|
||||||
ADD_SCENE(infrared, learn, Learn)
|
ADD_SCENE(infrared, learn, Learn)
|
||||||
ADD_SCENE(infrared, learn_done, LearnDone)
|
ADD_SCENE(infrared, learn_done, LearnDone)
|
||||||
ADD_SCENE(infrared, learn_enter_name, LearnEnterName)
|
ADD_SCENE(infrared, learn_enter_name, LearnEnterName)
|
||||||
|
|||||||
@@ -82,9 +82,7 @@ bool infrared_scene_edit_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect);
|
scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(submenu_index == SubmenuIndexMoveButton) {
|
} else if(submenu_index == SubmenuIndexMoveButton) {
|
||||||
infrared->app_state.edit_target = InfraredEditTargetButton;
|
scene_manager_next_scene(scene_manager, InfraredSceneEditMove);
|
||||||
infrared->app_state.edit_mode = InfraredEditModeMove;
|
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(submenu_index == SubmenuIndexDeleteButton) {
|
} else if(submenu_index == SubmenuIndexDeleteButton) {
|
||||||
infrared->app_state.edit_target = InfraredEditTargetButton;
|
infrared->app_state.edit_target = InfraredEditTargetButton;
|
||||||
|
|||||||
@@ -11,23 +11,9 @@ void infrared_scene_edit_button_select_on_enter(void* context) {
|
|||||||
InfraredRemote* remote = infrared->remote;
|
InfraredRemote* remote = infrared->remote;
|
||||||
InfraredAppState* app_state = &infrared->app_state;
|
InfraredAppState* app_state = &infrared->app_state;
|
||||||
|
|
||||||
const char* header = NULL;
|
const char* header = infrared->app_state.edit_mode == InfraredEditModeRename ?
|
||||||
switch(infrared->app_state.edit_mode) {
|
"Rename Button:" :
|
||||||
case InfraredEditModeRename:
|
"Delete Button:";
|
||||||
header = "Rename Button:";
|
|
||||||
break;
|
|
||||||
case InfraredEditModeDelete:
|
|
||||||
header = "Delete Button:";
|
|
||||||
break;
|
|
||||||
case InfraredEditModeMove:
|
|
||||||
header = "Select Button to Move:";
|
|
||||||
break;
|
|
||||||
case InfraredEditModeMoveSelectDest:
|
|
||||||
case InfraredEditModeNone:
|
|
||||||
default:
|
|
||||||
header = "Move Button Before:";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
submenu_set_header(submenu, header);
|
submenu_set_header(submenu, header);
|
||||||
|
|
||||||
const size_t button_count = infrared_remote_get_button_count(remote);
|
const size_t button_count = infrared_remote_get_button_count(remote);
|
||||||
@@ -40,14 +26,6 @@ void infrared_scene_edit_button_select_on_enter(void* context) {
|
|||||||
infrared_scene_edit_button_select_submenu_callback,
|
infrared_scene_edit_button_select_submenu_callback,
|
||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
if(infrared->app_state.edit_mode == InfraredEditModeMoveSelectDest) {
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"-- Move to the end --",
|
|
||||||
button_count,
|
|
||||||
infrared_scene_edit_button_select_submenu_callback,
|
|
||||||
context);
|
|
||||||
}
|
|
||||||
if(button_count && app_state->current_button_index != InfraredButtonIndexNone) {
|
if(button_count && app_state->current_button_index != InfraredButtonIndexNone) {
|
||||||
submenu_set_selected_item(submenu, app_state->current_button_index);
|
submenu_set_selected_item(submenu, app_state->current_button_index);
|
||||||
app_state->current_button_index = InfraredButtonIndexNone;
|
app_state->current_button_index = InfraredButtonIndexNone;
|
||||||
@@ -69,12 +47,6 @@ bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent
|
|||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditRename);
|
scene_manager_next_scene(scene_manager, InfraredSceneEditRename);
|
||||||
} else if(edit_mode == InfraredEditModeDelete) {
|
} else if(edit_mode == InfraredEditModeDelete) {
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditDelete);
|
scene_manager_next_scene(scene_manager, InfraredSceneEditDelete);
|
||||||
} else if(edit_mode == InfraredEditModeMove) {
|
|
||||||
app_state->current_button_index_move_orig = event.event;
|
|
||||||
app_state->edit_mode = InfraredEditModeMoveSelectDest;
|
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect);
|
|
||||||
} else if(edit_mode == InfraredEditModeMoveSelectDest) {
|
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditMove);
|
|
||||||
} else {
|
} else {
|
||||||
furi_assert(0);
|
furi_assert(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,103 +1,44 @@
|
|||||||
#include "../infrared_i.h"
|
#include "../infrared_i.h"
|
||||||
|
|
||||||
static void infrared_scene_edit_move_dialog_result_callback(DialogExResult result, void* context) {
|
static void infrared_scene_move_button(uint32_t index_old, uint32_t index_new, void* context) {
|
||||||
Infrared* infrared = context;
|
InfraredRemote* remote = context;
|
||||||
view_dispatcher_send_custom_event(infrared->view_dispatcher, result);
|
furi_assert(remote);
|
||||||
|
infrared_remote_move_button(remote, index_old, index_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* infrared_scene_get_btn_name(uint32_t index, void* context) {
|
||||||
|
InfraredRemote* remote = context;
|
||||||
|
furi_assert(remote);
|
||||||
|
InfraredRemoteButton* button = infrared_remote_get_button(remote, index);
|
||||||
|
return (infrared_remote_button_get_name(button));
|
||||||
}
|
}
|
||||||
|
|
||||||
void infrared_scene_edit_move_on_enter(void* context) {
|
void infrared_scene_edit_move_on_enter(void* context) {
|
||||||
Infrared* infrared = context;
|
Infrared* infrared = context;
|
||||||
DialogEx* dialog_ex = infrared->dialog_ex;
|
|
||||||
InfraredRemote* remote = infrared->remote;
|
InfraredRemote* remote = infrared->remote;
|
||||||
|
|
||||||
const InfraredEditTarget edit_target = infrared->app_state.edit_target;
|
infrared_move_view_set_callback(infrared->move_view, infrared_scene_move_button);
|
||||||
if(edit_target == InfraredEditTargetButton) {
|
|
||||||
int32_t current_button_index = infrared->app_state.current_button_index_move_orig;
|
|
||||||
furi_assert(current_button_index != InfraredButtonIndexNone);
|
|
||||||
|
|
||||||
dialog_ex_set_header(dialog_ex, "Move Button?", 64, 0, AlignCenter, AlignTop);
|
uint32_t btn_count = infrared_remote_get_button_count(remote);
|
||||||
InfraredRemoteButton* current_button =
|
infrared_move_view_list_init(
|
||||||
infrared_remote_get_button(remote, current_button_index);
|
infrared->move_view, btn_count, infrared_scene_get_btn_name, remote);
|
||||||
InfraredSignal* signal = infrared_remote_button_get_signal(current_button);
|
infrared_move_view_list_update(infrared->move_view);
|
||||||
|
|
||||||
if(infrared_signal_is_raw(signal)) {
|
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewMove);
|
||||||
const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
|
|
||||||
infrared_text_store_set(
|
|
||||||
infrared,
|
|
||||||
0,
|
|
||||||
"%s\nRAW\n%ld samples",
|
|
||||||
infrared_remote_button_get_name(current_button),
|
|
||||||
raw->timings_size);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const InfraredMessage* message = infrared_signal_get_message(signal);
|
|
||||||
infrared_text_store_set(
|
|
||||||
infrared,
|
|
||||||
0,
|
|
||||||
"%s\n%s\nA=0x%0*lX C=0x%0*lX",
|
|
||||||
infrared_remote_button_get_name(current_button),
|
|
||||||
infrared_get_protocol_name(message->protocol),
|
|
||||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4),
|
|
||||||
message->address,
|
|
||||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
|
||||||
message->command);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog_ex_set_text(dialog_ex, infrared->text_store[0], 64, 31, AlignCenter, AlignCenter);
|
|
||||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "Move");
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, infrared_scene_edit_move_dialog_result_callback);
|
|
||||||
dialog_ex_set_context(dialog_ex, context);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) {
|
bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) {
|
||||||
Infrared* infrared = context;
|
Infrared* infrared = context;
|
||||||
SceneManager* scene_manager = infrared->scene_manager;
|
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
UNUSED(event);
|
||||||
if(event.event == DialogExResultLeft) {
|
UNUSED(infrared);
|
||||||
scene_manager_previous_scene(scene_manager);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == DialogExResultRight) {
|
|
||||||
bool success = false;
|
|
||||||
InfraredRemote* remote = infrared->remote;
|
|
||||||
InfraredAppState* app_state = &infrared->app_state;
|
|
||||||
const InfraredEditTarget edit_target = app_state->edit_target;
|
|
||||||
|
|
||||||
if(edit_target == InfraredEditTargetButton) {
|
|
||||||
furi_assert(app_state->current_button_index != InfraredButtonIndexNone);
|
|
||||||
success = infrared_remote_move_button(
|
|
||||||
remote,
|
|
||||||
app_state->current_button_index_move_orig,
|
|
||||||
app_state->current_button_index);
|
|
||||||
app_state->current_button_index_move_orig = InfraredButtonIndexNone;
|
|
||||||
app_state->current_button_index = InfraredButtonIndexNone;
|
|
||||||
} else {
|
|
||||||
furi_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(success) {
|
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneEditMoveDone);
|
|
||||||
} else {
|
|
||||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
|
|
||||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
|
||||||
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
|
||||||
}
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void infrared_scene_edit_move_on_exit(void* context) {
|
void infrared_scene_edit_move_on_exit(void* context) {
|
||||||
Infrared* infrared = context;
|
Infrared* infrared = context;
|
||||||
UNUSED(infrared);
|
InfraredRemote* remote = infrared->remote;
|
||||||
|
infrared_remote_store(remote);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#include "../infrared_i.h"
|
|
||||||
|
|
||||||
void infrared_scene_edit_move_done_on_enter(void* context) {
|
|
||||||
Infrared* infrared = context;
|
|
||||||
Popup* popup = infrared->popup;
|
|
||||||
|
|
||||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
|
||||||
popup_set_header(popup, "Moved", 83, 19, AlignLeft, AlignBottom);
|
|
||||||
|
|
||||||
popup_set_callback(popup, infrared_popup_closed_callback);
|
|
||||||
popup_set_context(popup, context);
|
|
||||||
popup_set_timeout(popup, 1500);
|
|
||||||
popup_enable_timeout(popup);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool infrared_scene_edit_move_done_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Infrared* infrared = context;
|
|
||||||
SceneManager* scene_manager = infrared->scene_manager;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == InfraredCustomEventTypePopupClosed) {
|
|
||||||
const InfraredEditTarget edit_target = infrared->app_state.edit_target;
|
|
||||||
if(edit_target == InfraredEditTargetButton) {
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
scene_manager, InfraredSceneRemote);
|
|
||||||
} else if(edit_target == InfraredEditTargetRemote) {
|
|
||||||
const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList};
|
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene_one_of(
|
|
||||||
scene_manager, possible_scenes, COUNT_OF(possible_scenes))) {
|
|
||||||
view_dispatcher_stop(infrared->view_dispatcher);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_assert(0);
|
|
||||||
}
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void infrared_scene_edit_move_done_on_exit(void* context) {
|
|
||||||
Infrared* infrared = context;
|
|
||||||
UNUSED(infrared);
|
|
||||||
}
|
|
||||||
215
applications/main/infrared/views/infrared_move_view.c
Normal file
215
applications/main/infrared/views/infrared_move_view.c
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
#include "infrared_move_view.h"
|
||||||
|
|
||||||
|
#include <gui/canvas.h>
|
||||||
|
#include <gui/elements.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LIST_ITEMS 4U
|
||||||
|
#define LIST_LINE_H 13U
|
||||||
|
#define HEADER_H 12U
|
||||||
|
#define MOVE_X_OFFSET 5U
|
||||||
|
|
||||||
|
struct InfraredMoveView {
|
||||||
|
View* view;
|
||||||
|
InfraredMoveCallback move_cb;
|
||||||
|
void* cb_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char** btn_names;
|
||||||
|
uint32_t btn_number;
|
||||||
|
int32_t list_offset;
|
||||||
|
int32_t item_idx;
|
||||||
|
bool is_moving;
|
||||||
|
|
||||||
|
InfraredMoveGetItemCallback get_item_cb;
|
||||||
|
} InfraredMoveViewModel;
|
||||||
|
|
||||||
|
static void infrared_move_view_draw_callback(Canvas* canvas, void* _model) {
|
||||||
|
InfraredMoveViewModel* model = _model;
|
||||||
|
|
||||||
|
UNUSED(model);
|
||||||
|
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
elements_multiline_text_aligned(
|
||||||
|
canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "Select a button to move");
|
||||||
|
|
||||||
|
bool show_scrollbar = model->btn_number > LIST_ITEMS;
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < MIN(model->btn_number, LIST_ITEMS); i++) {
|
||||||
|
int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->btn_number, 0u);
|
||||||
|
uint8_t x_offset = (model->is_moving && model->item_idx == idx) ? MOVE_X_OFFSET : 0;
|
||||||
|
uint8_t y_offset = HEADER_H + i * LIST_LINE_H;
|
||||||
|
uint8_t box_end_x = canvas_width(canvas) - (show_scrollbar ? 6 : 1);
|
||||||
|
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
if(model->item_idx == idx) {
|
||||||
|
canvas_draw_box(canvas, x_offset, y_offset, box_end_x - x_offset, LIST_LINE_H);
|
||||||
|
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
canvas_draw_dot(canvas, x_offset, y_offset);
|
||||||
|
canvas_draw_dot(canvas, x_offset + 1, y_offset);
|
||||||
|
canvas_draw_dot(canvas, x_offset, y_offset + 1);
|
||||||
|
canvas_draw_dot(canvas, x_offset, y_offset + LIST_LINE_H - 1);
|
||||||
|
canvas_draw_dot(canvas, box_end_x - 1, y_offset);
|
||||||
|
canvas_draw_dot(canvas, box_end_x - 1, y_offset + LIST_LINE_H - 1);
|
||||||
|
}
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, x_offset + 3, y_offset + 3, AlignLeft, AlignTop, model->btn_names[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(show_scrollbar) {
|
||||||
|
elements_scrollbar_pos(
|
||||||
|
canvas,
|
||||||
|
canvas_width(canvas),
|
||||||
|
HEADER_H,
|
||||||
|
canvas_height(canvas) - HEADER_H,
|
||||||
|
model->item_idx,
|
||||||
|
model->btn_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_list_offset(InfraredMoveViewModel* model) {
|
||||||
|
int32_t bounds = model->btn_number > (LIST_ITEMS - 1) ? 2 : model->btn_number;
|
||||||
|
|
||||||
|
if((model->btn_number > (LIST_ITEMS - 1)) &&
|
||||||
|
(model->item_idx >= ((int32_t)model->btn_number - 1))) {
|
||||||
|
model->list_offset = model->item_idx - (LIST_ITEMS - 1);
|
||||||
|
} else if(model->list_offset < model->item_idx - bounds) {
|
||||||
|
model->list_offset = CLAMP(
|
||||||
|
model->item_idx - (int32_t)(LIST_ITEMS - 2), (int32_t)model->btn_number - bounds, 0);
|
||||||
|
} else if(model->list_offset > model->item_idx - bounds) {
|
||||||
|
model->list_offset = CLAMP(model->item_idx - 1, (int32_t)model->btn_number - bounds, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool infrared_move_view_input_callback(InputEvent* event, void* context) {
|
||||||
|
InfraredMoveView* move_view = context;
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(((event->type == InputTypeShort || event->type == InputTypeRepeat)) &&
|
||||||
|
((event->key == InputKeyUp) || (event->key == InputKeyDown))) {
|
||||||
|
bool is_moving = false;
|
||||||
|
uint32_t index_old = 0;
|
||||||
|
uint32_t index_new = 0;
|
||||||
|
with_view_model(
|
||||||
|
move_view->view,
|
||||||
|
InfraredMoveViewModel * model,
|
||||||
|
{
|
||||||
|
is_moving = model->is_moving;
|
||||||
|
index_old = model->item_idx;
|
||||||
|
if(event->key == InputKeyUp) {
|
||||||
|
if(model->item_idx <= 0) {
|
||||||
|
model->item_idx = model->btn_number;
|
||||||
|
}
|
||||||
|
model->item_idx--;
|
||||||
|
} else if(event->key == InputKeyDown) {
|
||||||
|
model->item_idx++;
|
||||||
|
if(model->item_idx >= (int32_t)(model->btn_number)) {
|
||||||
|
model->item_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index_new = model->item_idx;
|
||||||
|
update_list_offset(model);
|
||||||
|
},
|
||||||
|
!is_moving);
|
||||||
|
if((is_moving) && (move_view->move_cb)) {
|
||||||
|
move_view->move_cb(index_old, index_new, move_view->cb_context);
|
||||||
|
infrared_move_view_list_update(move_view);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((event->key == InputKeyOk) && (event->type == InputTypeShort)) {
|
||||||
|
with_view_model(
|
||||||
|
move_view->view,
|
||||||
|
InfraredMoveViewModel * model,
|
||||||
|
{ model->is_moving = !(model->is_moving); },
|
||||||
|
true);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void infrared_move_view_on_exit(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
InfraredMoveView* move_view = context;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
move_view->view,
|
||||||
|
InfraredMoveViewModel * model,
|
||||||
|
{
|
||||||
|
if(model->btn_names) {
|
||||||
|
free(model->btn_names);
|
||||||
|
model->btn_names = NULL;
|
||||||
|
}
|
||||||
|
model->btn_number = 0;
|
||||||
|
model->get_item_cb = NULL;
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
move_view->cb_context = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_move_view_set_callback(InfraredMoveView* move_view, InfraredMoveCallback callback) {
|
||||||
|
furi_assert(move_view);
|
||||||
|
move_view->move_cb = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_move_view_list_init(
|
||||||
|
InfraredMoveView* move_view,
|
||||||
|
uint32_t item_count,
|
||||||
|
InfraredMoveGetItemCallback load_cb,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(move_view);
|
||||||
|
move_view->cb_context = context;
|
||||||
|
with_view_model(
|
||||||
|
move_view->view,
|
||||||
|
InfraredMoveViewModel * model,
|
||||||
|
{
|
||||||
|
furi_assert(model->btn_names == NULL);
|
||||||
|
model->btn_names = malloc(sizeof(char*) * item_count);
|
||||||
|
model->btn_number = item_count;
|
||||||
|
model->get_item_cb = load_cb;
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_move_view_list_update(InfraredMoveView* move_view) {
|
||||||
|
furi_assert(move_view);
|
||||||
|
with_view_model(
|
||||||
|
move_view->view,
|
||||||
|
InfraredMoveViewModel * model,
|
||||||
|
{
|
||||||
|
for(uint32_t i = 0; i < model->btn_number; i++) {
|
||||||
|
if(!model->get_item_cb) break;
|
||||||
|
model->btn_names[i] = model->get_item_cb(i, move_view->cb_context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
InfraredMoveView* infrared_move_view_alloc(void) {
|
||||||
|
InfraredMoveView* move_view = malloc(sizeof(InfraredMoveView));
|
||||||
|
move_view->view = view_alloc();
|
||||||
|
view_allocate_model(move_view->view, ViewModelTypeLocking, sizeof(InfraredMoveViewModel));
|
||||||
|
view_set_draw_callback(move_view->view, infrared_move_view_draw_callback);
|
||||||
|
view_set_input_callback(move_view->view, infrared_move_view_input_callback);
|
||||||
|
view_set_exit_callback(move_view->view, infrared_move_view_on_exit);
|
||||||
|
view_set_context(move_view->view, move_view);
|
||||||
|
return move_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_move_view_free(InfraredMoveView* move_view) {
|
||||||
|
view_free(move_view->view);
|
||||||
|
free(move_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* infrared_move_view_get_view(InfraredMoveView* move_view) {
|
||||||
|
return move_view->view;
|
||||||
|
}
|
||||||
25
applications/main/infrared/views/infrared_move_view.h
Normal file
25
applications/main/infrared/views/infrared_move_view.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
typedef struct InfraredMoveView InfraredMoveView;
|
||||||
|
|
||||||
|
typedef void (*InfraredMoveCallback)(uint32_t index_old, uint32_t index_new, void* context);
|
||||||
|
|
||||||
|
typedef const char* (*InfraredMoveGetItemCallback)(uint32_t index, void* context);
|
||||||
|
|
||||||
|
InfraredMoveView* infrared_move_view_alloc(void);
|
||||||
|
|
||||||
|
void infrared_move_view_free(InfraredMoveView* debug_view);
|
||||||
|
|
||||||
|
View* infrared_move_view_get_view(InfraredMoveView* debug_view);
|
||||||
|
|
||||||
|
void infrared_move_view_set_callback(InfraredMoveView* move_view, InfraredMoveCallback callback);
|
||||||
|
|
||||||
|
void infrared_move_view_list_init(
|
||||||
|
InfraredMoveView* move_view,
|
||||||
|
uint32_t item_count,
|
||||||
|
InfraredMoveGetItemCallback load_cb,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
void infrared_move_view_list_update(InfraredMoveView* move_view);
|
||||||
@@ -53,18 +53,14 @@ ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess)
|
|||||||
ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard)
|
ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard)
|
||||||
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
|
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
|
||||||
ADD_SCENE(nfc, emv_menu, EmvMenu)
|
ADD_SCENE(nfc, emv_menu, EmvMenu)
|
||||||
#if FURI_DEBUG
|
|
||||||
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||||
#endif
|
|
||||||
ADD_SCENE(nfc, device_info, DeviceInfo)
|
ADD_SCENE(nfc, device_info, DeviceInfo)
|
||||||
ADD_SCENE(nfc, delete, Delete)
|
ADD_SCENE(nfc, delete, Delete)
|
||||||
ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
||||||
ADD_SCENE(nfc, restore_original_confirm, RestoreOriginalConfirm)
|
ADD_SCENE(nfc, restore_original_confirm, RestoreOriginalConfirm)
|
||||||
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
||||||
#if FURI_DEBUG
|
|
||||||
ADD_SCENE(nfc, debug, Debug)
|
ADD_SCENE(nfc, debug, Debug)
|
||||||
ADD_SCENE(nfc, field, Field)
|
ADD_SCENE(nfc, field, Field)
|
||||||
#endif
|
|
||||||
ADD_SCENE(nfc, dict_not_found, DictNotFound)
|
ADD_SCENE(nfc, dict_not_found, DictNotFound)
|
||||||
ADD_SCENE(nfc, rpc, Rpc)
|
ADD_SCENE(nfc, rpc, Rpc)
|
||||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#if FURI_DEBUG
|
|
||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
enum SubmenuDebugIndex {
|
enum SubmenuDebugIndex {
|
||||||
@@ -53,4 +52,3 @@ void nfc_scene_debug_on_exit(void* context) {
|
|||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
#if FURI_DEBUG
|
|
||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
#include <core/common_defines.h>
|
#include <core/common_defines.h>
|
||||||
|
|
||||||
@@ -33,4 +32,3 @@ void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
|
|||||||
|
|
||||||
nfc_blink_stop(nfc);
|
nfc_blink_stop(nfc);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
#if FURI_DEBUG
|
|
||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_field_on_enter(void* context) {
|
void nfc_scene_field_on_enter(void* context) {
|
||||||
@@ -32,4 +31,3 @@ void nfc_scene_field_on_exit(void* context) {
|
|||||||
notification_internal_message(nfc->notifications, &sequence_reset_blue);
|
notification_internal_message(nfc->notifications, &sequence_reset_blue);
|
||||||
popup_reset(nfc->popup);
|
popup_reset(nfc->popup);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
@@ -8,9 +8,7 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexSaved,
|
SubmenuIndexSaved,
|
||||||
SubmenuIndexExtraAction,
|
SubmenuIndexExtraAction,
|
||||||
SubmenuIndexAddManually,
|
SubmenuIndexAddManually,
|
||||||
#if FURI_DEBUG
|
|
||||||
SubmenuIndexDebug,
|
SubmenuIndexDebug,
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||||
@@ -31,12 +29,12 @@ void nfc_scene_start_on_enter(void* context) {
|
|||||||
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Add Manually", SubmenuIndexAddManually, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Add Manually", SubmenuIndexAddManually, nfc_scene_start_submenu_callback, nfc);
|
||||||
#if FURI_DEBUG
|
|
||||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
|
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
|
||||||
|
|
||||||
@@ -84,14 +82,11 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually);
|
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
} else if(event.event == SubmenuIndexDebug) {
|
||||||
#if FURI_DEBUG
|
|
||||||
else if(event.event == SubmenuIndexDebug) {
|
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
#define TAG "DesktopSrv"
|
#define TAG "DesktopSrv"
|
||||||
|
|
||||||
#define FAP_LOADER_APP_NAME "Applications"
|
|
||||||
|
|
||||||
static void desktop_scene_main_new_idle_animation_callback(void* context) {
|
static void desktop_scene_main_new_idle_animation_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Desktop* desktop = context;
|
Desktop* desktop = context;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ duty_cycle: 0.330000
|
|||||||
data: 8972 4491 592 1651 592 1655 598 532 599 535 597 542 600 541 601 544 598 1656 597 526 595 1652 591 1658 595 539 593 545 597 545 597 546 596 537 594 529 592 535 596 1653 600 534 597 541 601 539 592 552 600 533 598 525 596 530 591 538 593 539 592 1665 598 1662 591 1673 601 533 598 526 595 533 598 532 600 534 597 540 591 548 594 550 592 542 600 523 598 528 593 536 595 537 594 543 599 542 600 543 599 517 594 7937 593 531 601 526 595 535 597 537 594 542 600 541 601 543 599 1654 599 523 598 528 593 536 596 538 594 542 600 541 590 552 600 532 599 524 597 528 593 536 595 537 595 541 601 539 593 551 591 542 600 522 599 527 594 536 595 537 594 543 599 540 591 552 600 532 600 523 598 527 594 535 596 537 595 542 600 540 591 552 600 532 600 523 598 528 593 536 595 538 593 543 599 541 601 543 599 535 596 527 594 532 600 531 601 534 597 540 592 549 593 552 600 534 597 525 596 529 592 1655 598 534 597 1656 597 1661 592 1671 592 1644 599 7934 596 529 592 535 597 535 597 538 593 544 598 543 599 545 597 538 593 1650 593 535 596 534 597 536 595 540 591 547 595 547 595 536 595 526 595 529 592 536 595 535 596 539 593 546 596 547 595 538 593 528 593 531 601 529 592 541 601 536 596 545 597 548 594 540 592 532 600 526 595 535 596 1656 597 541 601 540 592 553 599 534 597 526 595 532 599 531 600 533 598 539 593 548 594 552 600 535 596 1647 596 531 590 538 593 1656 597 538 594 545 597 545 597 518 593
|
data: 8972 4491 592 1651 592 1655 598 532 599 535 597 542 600 541 601 544 598 1656 597 526 595 1652 591 1658 595 539 593 545 597 545 597 546 596 537 594 529 592 535 596 1653 600 534 597 541 601 539 592 552 600 533 598 525 596 530 591 538 593 539 592 1665 598 1662 591 1673 601 533 598 526 595 533 598 532 600 534 597 540 591 548 594 550 592 542 600 523 598 528 593 536 595 537 594 543 599 542 600 543 599 517 594 7937 593 531 601 526 595 535 597 537 594 542 600 541 601 543 599 1654 599 523 598 528 593 536 596 538 594 542 600 541 590 552 600 532 599 524 597 528 593 536 595 537 595 541 601 539 593 551 591 542 600 522 599 527 594 536 595 537 594 543 599 540 591 552 600 532 600 523 598 527 594 535 596 537 595 542 600 540 591 552 600 532 600 523 598 528 593 536 595 538 593 543 599 541 601 543 599 535 596 527 594 532 600 531 601 534 597 540 592 549 593 552 600 534 597 525 596 529 592 1655 598 534 597 1656 597 1661 592 1671 592 1644 599 7934 596 529 592 535 597 535 597 538 593 544 598 543 599 545 597 538 593 1650 593 535 596 534 597 536 595 540 591 547 595 547 595 536 595 526 595 529 592 536 595 535 596 539 593 546 596 547 595 538 593 528 593 531 601 529 592 541 601 536 596 545 597 548 594 540 592 532 600 526 595 535 596 1656 597 541 601 540 592 553 599 534 597 526 595 532 599 531 600 533 598 539 593 548 594 552 600 535 596 1647 596 531 590 538 593 1656 597 538 594 545 597 545 597 518 593
|
||||||
#
|
#
|
||||||
# Model: Daichi DA25AVQS1-W
|
# Model: Daichi DA25AVQS1-W
|
||||||
|
# Compatible Brands: Gree, Tosot
|
||||||
name: Dh
|
name: Dh
|
||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
@@ -100,7 +101,7 @@ name: Heat_hi
|
|||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 148 110377 9082 4422 707 499 706 500 704 1603 703 1606 701 505 700 507 699 506 700 507 699 506 700 1607 700 1608 700 1609 699 506 699 507 699 506 699 507 699 507 699 506 700 507 699 507 699 507 699 1608 699 1607 699 507 699 507 699 507 699 507 699 507 699 1609 699 507 699 1608 699 507 699 507 699 1609 699 507 699 19940 700 506 700 506 699 507 699 507 699 506 700 506 700 507 699 507 699 507 700 507 699 506 699 507 699 507 699 507 699 507 699 507 699 507 699 507 699 507 698 507 700 507 699 507 699 507 699 507 699 507 699 508 698 508 698 507 699 507 699 508 698 1610 699 508 698
|
data: 9082 4422 707 499 706 500 704 1603 703 1606 701 505 700 507 699 506 700 507 699 506 700 1607 700 1608 700 1609 699 506 699 507 699 506 699 507 699 507 699 506 700 507 699 507 699 507 699 1608 699 1607 699 507 699 507 699 507 699 507 699 507 699 1609 699 507 699 1608 699 507 699 507 699 1609 699 507 699 19940 700 506 700 506 699 507 699 507 699 506 700 506 700 507 699 507 699 507 700 507 699 506 699 507 699 507 699 507 699 507 699 507 699 507 699 507 699 507 698 507 700 507 699 507 699 507 699 507 699 507 699 508 698 508 698 507 699 507 699 508 698 1610 699 508 698
|
||||||
#
|
#
|
||||||
name: Heat_lo
|
name: Heat_lo
|
||||||
type: raw
|
type: raw
|
||||||
@@ -225,13 +226,13 @@ name: Cool_hi
|
|||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 315 101050 3094 3056 3093 4437 580 1648 572 534 576 1649 582 525 574 530 580 1646 574 1653 578 529 570 534 576 529 571 534 576 529 570 1655 576 1651 580 527 572 532 578 1647 573 1654 577 1651 580 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 525 574 531 579 525 574 531 579 1646 574 532 578 526 573 531 579 526 573 531 579 526 573 1652 579 527 572 1653 578 528 571 534 576 528 571 533 577 528 571 533 577 528 572 533 577 528 572 532 578 527 572 532 578 527 572 532 578 526 573 1652 579 527 572 532 578 527 572 532 578 527 572 532 578 526 573 531 579 526 573 531 579 526 573 531 579 525 574 530 580 525 574 530 580 525 574 530 580 524 575 529 581 524 575 529 571 534 576 528 571 533 577 528 571 533 577 528 571 533 577 527 572 532 578 527 572 532 578 526 573 531 579 526 573 531 579 525 574 531 579 525 574 530 580 525 574 1650 581 525 574 1651 580 1647 573 533 577 527 572 1653 578 528 572 1654 577 1650 581 1646 574 71637 254
|
data: 3094 3056 3093 4437 580 1648 572 534 576 1649 582 525 574 530 580 1646 574 1653 578 529 570 534 576 529 571 534 576 529 570 1655 576 1651 580 527 572 532 578 1647 573 1654 577 1651 580 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 525 574 531 579 525 574 531 579 1646 574 532 578 526 573 531 579 526 573 531 579 526 573 1652 579 527 572 1653 578 528 571 534 576 528 571 533 577 528 571 533 577 528 572 533 577 528 572 532 578 527 572 532 578 527 572 532 578 526 573 1652 579 527 572 532 578 527 572 532 578 527 572 532 578 526 573 531 579 526 573 531 579 526 573 531 579 525 574 530 580 525 574 530 580 525 574 530 580 524 575 529 581 524 575 529 571 534 576 528 571 533 577 528 571 533 577 528 571 533 577 527 572 532 578 527 572 532 578 526 573 531 579 526 573 531 579 525 574 531 579 525 574 530 580 525 574 1650 581 525 574 1651 580 1647 573 533 577 527 572 1653 578 528 572 1654 577 1650 581 1646 574 71637 254
|
||||||
#
|
#
|
||||||
name: Cool_lo
|
name: Cool_lo
|
||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 284 19161 3098 3053 3096 4435 572 1656 575 532 578 1648 572 534 576 530 570 1682 549 1652 579 527 572 534 576 1649 571 1656 575 1652 579 1649 571 1656 575 531 579 527 572 1653 578 1649 571 1656 575 531 579 527 572 532 578 527 572 533 577 527 572 533 577 527 573 532 578 527 572 532 578 527 573 532 578 527 572 1652 579 527 572 533 577 528 571 533 577 528 571 533 577 1648 572 533 577 1649 571 535 575 530 569 536 574 531 569 536 574 530 569 536 574 530 570 535 575 530 570 535 575 530 569 535 575 530 569 535 575 1649 571 535 575 531 568 536 574 531 568 536 574 531 568 536 574 531 569 536 574 530 569 536 574 530 569 535 575 530 569 535 575 530 569 535 575 530 570 535 575 529 570 534 576 529 570 534 576 529 570 534 576 528 571 534 576 528 571 534 576 528 571 534 576 528 571 534 576 528 571 533 577 528 571 533 577 528 572 533 577 528 571 533 577 528 572 1652 579 527 572 1653 578 529 570 534 576 529 570 535 575 529 570 1654 577 1677 554 1673 547
|
data: 3098 3053 3096 4435 572 1656 575 532 578 1648 572 534 576 530 570 1682 549 1652 579 527 572 534 576 1649 571 1656 575 1652 579 1649 571 1656 575 531 579 527 572 1653 578 1649 571 1656 575 531 579 527 572 532 578 527 572 533 577 527 572 533 577 527 573 532 578 527 572 532 578 527 573 532 578 527 572 1652 579 527 572 533 577 528 571 533 577 528 571 533 577 1648 572 533 577 1649 571 535 575 530 569 536 574 531 569 536 574 530 569 536 574 530 570 535 575 530 570 535 575 530 569 535 575 530 569 535 575 1649 571 535 575 531 568 536 574 531 568 536 574 531 568 536 574 531 569 536 574 530 569 536 574 530 569 535 575 530 569 535 575 530 569 535 575 530 570 535 575 529 570 534 576 529 570 534 576 529 570 534 576 528 571 534 576 528 571 534 576 528 571 534 576 528 571 534 576 528 571 533 577 528 571 533 577 528 572 533 577 528 571 533 577 528 572 1652 579 527 572 1653 578 529 570 534 576 529 570 535 575 529 570 1654 577 1677 554 1673 547
|
||||||
#
|
#
|
||||||
name: Off
|
name: Off
|
||||||
type: raw
|
type: raw
|
||||||
@@ -256,7 +257,7 @@ name: Cool_lo
|
|||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 301 132136 5036 2167 337 1766 361 689 358 692 366 684 363 1770 357 692 366 684 363 718 329 690 357 1776 361 687 360 1773 364 1767 360 689 358 1775 362 1769 357 1774 363 1768 359 1773 364 684 363 718 329 1773 364 684 363 718 329 691 356 694 364 716 331 719 328 1775 362 1769 358 1774 363 1768 359 1772 365 714 333 1770 357 1774 363 716 331 719 328 722 336 715 332 718 329 721 326 724 334 716 331 719 328 722 336 715 332 718 329 1773 364 1767 360 1772 354 1777 360 719 328 721 326 725 333 717 330 29455 5036 2139 354 1777 360 688 359 691 367 714 333 1770 356 692 366 684 363 687 360 690 357 1776 361 688 359 1773 364 1768 359 689 358 1775 362 1769 357 1774 363 1768 359 1773 364 684 363 687 360 1773 364 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 688 359 691 356 1777 360 1771 355 693 365 685 362 1771 355 693 365 1768 359 1773 364 1767 360 689 358 692 366 685 362 1771 355 1775 362 687 360 690 357 1775 362 687 360 690 357 693 365 716 331 689 358 1774 363 686 361 689 358 692 366 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 1771 355 693 365 1768 358 1773 364 684 363 687 360 690 357 693 365 1768 359 690 357 1776 361 688 359 691 356 694 364 686 361 689 358 692 366 685 362 1770 356 693 365 685 362 688 359 691 356 1777 360 1771 355 693 365 686 361 689 358 692 366 685 362 1770 356
|
data: 5036 2167 337 1766 361 689 358 692 366 684 363 1770 357 692 366 684 363 718 329 690 357 1776 361 687 360 1773 364 1767 360 689 358 1775 362 1769 357 1774 363 1768 359 1773 364 684 363 718 329 1773 364 684 363 718 329 691 356 694 364 716 331 719 328 1775 362 1769 358 1774 363 1768 359 1772 365 714 333 1770 357 1774 363 716 331 719 328 722 336 715 332 718 329 721 326 724 334 716 331 719 328 722 336 715 332 718 329 1773 364 1767 360 1772 354 1777 360 719 328 721 326 725 333 717 330 29455 5036 2139 354 1777 360 688 359 691 367 714 333 1770 356 692 366 684 363 687 360 690 357 1776 361 688 359 1773 364 1768 359 689 358 1775 362 1769 357 1774 363 1768 359 1773 364 684 363 687 360 1773 364 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 688 359 691 356 1777 360 1771 355 693 365 685 362 1771 355 693 365 1768 359 1773 364 1767 360 689 358 692 366 685 362 1771 355 1775 362 687 360 690 357 1775 362 687 360 690 357 693 365 716 331 689 358 1774 363 686 361 689 358 692 366 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 688 359 691 356 694 364 686 361 689 358 692 366 685 362 1771 355 693 365 1768 358 1773 364 684 363 687 360 690 357 693 365 1768 359 690 357 1776 361 688 359 691 356 694 364 686 361 689 358 692 366 685 362 1770 356 693 365 685 362 688 359 691 356 1777 360 1771 355 693 365 686 361 689 358 692 366 685 362 1770 356
|
||||||
#
|
#
|
||||||
name: Off
|
name: Off
|
||||||
type: raw
|
type: raw
|
||||||
@@ -511,80 +512,42 @@ frequency: 38000
|
|||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 6059 7355 592 1633 592 1633 592 1633 592 1633 592 1633 592 1633 592 1633 618 1608 617 489 617 490 616 490 616 491 590 517 589 517 614 492 590 517 590 1636 589 1636 590 1636 590 1636 589 1636 590 1636 590 1636 590 1636 590 517 589 517 589 517 589 517 590 517 589 517 589 517 589 517 589 517 589 1636 614 492 590 1636 590 1636 590 1636 589 1636 590 1636 589 1637 589 517 589 1636 590 517 589 517 589 517 614 492 590 517 589 1636 590 517 589 1636 590 517 589 517 589 517 589 517 590 1636 590 517 589 1636 590 517 589 1636 589 1636 590 1636 590 1637 589 517 589 517 589 1637 588 1637 589 517 589 1637 589 1636 590 517 589 1636 590 1636 590 517 589 517 589 1637 589 517 589 517 589 1637 589 517 589 518 588 1637 589 518 588 1637 589 517 590 1637 588 518 588 518 588 1637 589 518 588 1637 589 518 588 1637 589 518 588 1637 589 1637 589 7357 589
|
data: 6059 7355 592 1633 592 1633 592 1633 592 1633 592 1633 592 1633 592 1633 618 1608 617 489 617 490 616 490 616 491 590 517 589 517 614 492 590 517 590 1636 589 1636 590 1636 590 1636 589 1636 590 1636 590 1636 590 1636 590 517 589 517 589 517 589 517 590 517 589 517 589 517 589 517 589 517 589 1636 614 492 590 1636 590 1636 590 1636 589 1636 590 1636 589 1637 589 517 589 1636 590 517 589 517 589 517 614 492 590 517 589 1636 590 517 589 1636 590 517 589 517 589 517 589 517 590 1636 590 517 589 1636 590 517 589 1636 589 1636 590 1636 590 1637 589 517 589 517 589 1637 588 1637 589 517 589 1637 589 1636 590 517 589 1636 590 1636 590 517 589 517 589 1637 589 517 589 517 589 1637 589 517 589 518 588 1637 589 518 588 1637 589 517 590 1637 588 518 588 518 588 1637 589 518 588 1637 589 518 588 1637 589 518 588 1637 589 1637 589 7357 589
|
||||||
#
|
#
|
||||||
# Model: Tosot T24H-ILF/I/T24H-ILU/O
|
|
||||||
# Compatible Brands: Gree
|
|
||||||
name: Off
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9072 4445 602 1586 603 477 601 478 600 479 599 480 598 481 598 482 597 482 572 1617 597 1593 572 1617 597 483 572 507 572 507 572 507 572 507 572 507 597 482 597 482 572 507 597 482 572 1618 571 507 572 507 572 507 572 507 572 507 572 507 572 1618 571 507 572 1618 572 507 572 507 572 1618 572 507 652 20153 572 507 597 482 572 507 572 507 597 482 597 482 572 507 596 483 572 507 572 507 572 507 572 507 572 507 572 1618 596 483 572 507 596 483 595 484 572 507 597 482 595 484 597 482 597 482 572 507 572 507 597 482 572 507 597 482 572 507 597 483 571 1618 597 482 675 40391 9179 4421 599 1590 599 481 597 482 597 482 597 481 598 482 597 482 597 482 597 1592 597 1592 598 1592 597 482 597 482 597 482 597 482 597 482 597 482 597 482 597 482 597 482 572 507 597 1593 597 482 572 507 572 507 572 507 572 507 572 508 571 1618 597 1593 596 1593 572 507 572 507 572 1618 597 482 678 20152 597 483 596 482 597 482 597 482 597 482 597 482 572 507 597 482 597 482 597 482 572 507 597 482 597 482 597 482 597 482 597 482 572 507 597 482 597 482 572 507 597 482 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 1618 596 482 572 507 572
|
|
||||||
#
|
|
||||||
name: Cool_hi
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9049 4446 575 1613 577 503 601 478 601 1590 599 480 598 482 572 507 572 507 572 508 571 507 572 507 572 507 572 508 571 508 571 507 573 507 572 508 571 508 572 507 572 508 571 507 572 1618 572 508 572 507 572 508 571 508 571 508 571 508 571 1618 572 508 571 1618 572 508 571 508 571 1619 571 508 651 20157 572 507 572 507 572 507 572 507 572 507 572 507 573 507 572 507 572 507 572 507 572 507 572 507 572 507 572 1618 572 507 572 507 572 507 572 507 573 507 572 508 571 507 572 508 571 507 572 507 573 507 572 507 572 507 572 508 571 1619 571 507 572 1618 572 508 651 40424 9180 4422 599 1591 598 482 597 483 572 1618 572 507 598 482 597 482 572 507 572 507 598 482 572 507 598 482 572 507 598 482 597 482 572 507 572 507 572 507 573 507 572 507 573 507 572 1618 572 507 598 482 572 507 572 507 597 483 596 483 597 1593 572 1618 572 1618 572 508 572 507 572 1618 572 508 678 20157 572 507 597 482 597 482 597 481 598 482 572 507 572 507 572 507 572 507 597 482 572 507 597 482 572 507 573 507 572 507 572 507 572 507 572 507 572 507 572 507 572 508 572 507 572 507 572 507 572 507 572 507 572 508 571 508 571 1619 571 1618 572 508 571 507 572
|
|
||||||
#
|
|
||||||
name: Cool_lo
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9075 4419 603 1586 603 476 602 478 600 1589 600 480 599 481 598 482 597 482 597 1593 597 1593 597 1593 597 482 597 482 572 507 572 507 596 483 573 507 572 507 573 507 598 482 572 507 573 1618 572 508 572 507 572 508 572 507 596 483 572 508 571 1618 596 484 572 1618 572 507 572 507 572 1618 572 508 651 20158 597 482 598 482 597 482 597 482 597 482 572 507 572 507 572 507 597 482 597 483 597 482 572 507 573 507 597 1594 572 507 597 482 572 507 597 482 598 482 572 508 571 508 571 508 572 507 572 507 597 482 597 483 572 508 571 508 571 508 596 483 597 1593 596 1593 652 40424 9181 4422 599 1591 598 481 598 482 572 1618 598 482 597 481 598 482 598 481 598 1593 597 1593 597 1592 598 482 598 482 597 482 597 482 598 482 597 482 597 482 598 482 597 482 597 482 598 1593 597 482 597 482 597 482 597 483 597 482 572 508 597 1593 596 1594 597 1593 597 483 571 508 571 1618 572 508 678 20157 572 507 572 507 573 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 573 507 572 507 573 507 572 507 573 507 572 507 572 507 572 507 572 508 571 507 572 508 571 508 571 508 571 508 572 1618 572 508 571 1618 572
|
|
||||||
#
|
|
||||||
name: Heat_lo
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9048 4447 576 503 576 503 601 1589 600 1590 599 481 573 507 572 507 572 507 572 1618 572 1618 572 1618 572 507 572 507 573 507 572 508 572 507 572 507 572 507 572 507 572 507 572 507 572 1618 572 507 573 507 572 508 571 507 572 507 572 508 571 1618 572 507 572 1618 572 508 571 507 572 1618 572 508 651 20157 572 507 572 507 572 507 572 507 572 508 572 507 572 507 572 507 572 508 571 508 572 508 571 508 571 508 571 1619 571 507 572 508 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 509 570 509 570 1620 570 1620 570 1620 570 1620 649 40424 9153 4450 573 506 573 507 572 1619 571 1618 572 508 571 508 571 508 572 508 571 1619 571 1619 571 1619 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 508 571 509 570 509 571 1619 571 509 571 509 570 509 571 509 570 509 570 509 570 1620 570 1621 569 1644 546 509 570 509 570 1620 570 510 676 20158 571 508 572 507 572 508 571 508 571 508 571 508 571 508 571 508 572 508 571 508 571 508 571 508 572 508 571 508 571 508 571 508 571 509 570 509 570 509 571 509 570 509 570 534 545 511 568 533 546 534 546 533 546 534 545 534 545 1645 545 534 545 1645 545 1644 546
|
|
||||||
#
|
|
||||||
name: Heat_hi
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9072 4445 602 476 602 476 602 1588 600 1589 600 480 599 481 597 481 598 481 598 481 598 1592 598 1592 598 1592 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 482 597 482 597 1592 598 481 598 481 598 481 598 481 598 481 598 481 598 1592 598 481 598 1592 598 481 598 481 598 1592 598 481 678 20126 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 1592 597 481 598 481 598 481 599 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 482 597 481 598 481 598 1592 597 1592 597 481 677 40388 9180 4420 600 479 599 480 599 1591 599 1591 598 481 598 481 598 481 598 481 598 481 598 1591 598 1591 598 1591 599 480 599 481 598 481 598 481 598 481 598 481 598 481 598 481 598 481 598 1591 598 481 598 481 598 481 598 481 598 481 598 481 598 1591 598 1592 598 1591 598 481 598 481 598 1592 598 481 704 20126 598 480 599 480 599 480 599 481 598 480 599 480 599 480 599 481 598 480 599 480 599 480 599 481 598 481 598 480 599 481 598 480 599 481 598 480 599 480 599 481 598 481 598 481 598 480 599 481 598 481 598 481 598 481 598 481 598 481 598 481 598 1591 599 481 598
|
|
||||||
#
|
|
||||||
name: Dh
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 9076 4445 577 503 602 1587 603 477 601 1589 600 1590 599 481 573 507 572 507 572 1618 572 1618 572 1618 572 507 572 507 573 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 572 1618 572 507 573 507 572 507 572 507 573 507 572 507 572 1618 572 507 573 1618 572 507 572 507 572 1618 572 507 652 20157 597 482 573 507 597 483 572 507 572 507 573 507 572 507 572 507 596 483 597 482 572 507 572 507 572 507 597 1593 572 507 572 507 573 507 572 507 572 507 572 507 572 507 572 507 572 507 572 507 596 484 572 507 572 507 572 507 597 1593 596 483 572 1618 572 1618 652 40424 9181 4422 599 480 598 1591 599 481 598 1592 598 1592 598 481 598 481 598 481 598 1592 598 1592 598 1592 598 481 598 481 598 481 598 482 597 481 598 481 599 481 598 482 598 482 597 482 598 1592 598 482 597 482 597 482 597 482 597 482 598 482 597 1593 597 1593 597 1592 598 482 598 482 596 1593 597 482 703 20132 598 481 598 481 599 481 598 481 598 481 598 481 598 481 598 481 598 482 598 481 598 482 597 482 597 482 597 482 598 482 598 481 598 481 598 482 597 482 598 482 598 1592 598 482 597 482 597 482 598 482 597 482 597 482 572 507 572 507 598 482 597 1593 597 1593 572
|
|
||||||
#
|
|
||||||
# Model: LG Generic
|
# Model: LG Generic
|
||||||
name: Off
|
name: Off
|
||||||
type: parsed
|
type: raw
|
||||||
protocol: NECext
|
frequency: 38000
|
||||||
address: 81 66 00 00
|
duty_cycle: 0.330000
|
||||||
command: 81 7E 00 00
|
data: 8518 4239 547 1511 572 495 547 495 571 470 572 1512 571 470 570 471 569 473 569 1515 568 1515 568 474 568 473 568 475 567 473 568 473 568 474 567 475 567 473 567 474 568 473 568 474 567 1516 567 474 567 1516 567 475 567 474 567 474 567 1517 567
|
||||||
#
|
#
|
||||||
name: Cool_hi
|
name: Cool_hi
|
||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 8725 4071 527 1527 501 521 501 517 500 520 500 1545 499 523 498 521 521 525 495 529 470 550 470 549 494 527 470 552 471 549 470 552 471 547 495 529 470 548 471 1572 470 1574 470 548 494 1551 470 547 470 552 470 551 470 1571 496 1547 469 1573 471
|
data: 8508 4216 570 1512 570 498 599 442 598 442 598 1485 597 445 595 446 594 448 566 476 566 475 566 476 566 475 566 475 566 476 565 474 566 475 566 476 566 474 566 475 566 1517 565 475 566 1518 566 475 567 1516 566 475 566 1516 567 1516 566 476 566
|
||||||
#
|
|
||||||
name: Heat_hi
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 8755 4064 528 1524 502 523 501 517 501 520 500 1543 500 519 498 524 497 523 497 527 496 521 496 525 521 500 496 527 496 1545 496 525 496 526 496 1545 495 1550 496 1541 496 1549 496 523 495 1546 496 526 496 523 521 499 496 1550 495 1544 495 1548 495
|
|
||||||
#
|
|
||||||
name: Heat_lo
|
|
||||||
type: raw
|
|
||||||
frequency: 38000
|
|
||||||
duty_cycle: 0.330000
|
|
||||||
data: 8783 4042 556 1497 502 521 501 518 501 520 500 1546 499 517 499 523 497 525 496 527 522 496 497 523 497 524 496 528 522 1516 521 500 496 526 497 1542 520 501 496 527 496 522 497 524 496 1548 496 521 521 500 521 500 520 503 497 521 521 500 497
|
|
||||||
#
|
#
|
||||||
name: Cool_lo
|
name: Cool_lo
|
||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 8721 4070 527 1526 501 524 501 517 501 518 500 1544 500 519 498 524 497 526 496 550 471 549 470 549 470 551 494 531 470 548 470 549 470 552 470 1572 494 526 494 528 470 551 470 549 470 1573 470 551 470 548 495 1548 470 1572 469 551 494 527 495
|
data: 8512 4239 546 1536 546 496 545 495 545 496 545 1539 569 471 568 473 542 499 542 500 542 499 542 501 541 499 542 499 542 500 542 499 542 500 541 1541 541 500 542 499 542 499 542 500 541 1542 542 500 541 1541 541 1541 542 1543 541 500 541 1542 540
|
||||||
#
|
#
|
||||||
name: Dh
|
name: Dh
|
||||||
type: raw
|
type: raw
|
||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 8780 4015 578 1498 553 471 526 494 525 494 524 1520 525 495 523 498 522 499 521 502 522 497 522 499 522 500 521 1519 522 500 521 499 521 1520 546 1496 521 503 523 494 522 500 521 499 522 1520 521 499 522 499 522 502 522 1518 521 501 521 1522 522
|
data: 8518 4238 546 1535 547 494 546 495 546 495 546 1537 545 497 544 497 543 498 543 499 542 500 542 499 542 500 542 500 541 499 542 500 541 1542 541 501 541 499 541 500 541 1542 541 499 541 499 541 500 541 500 541 499 541 500 541 1542 541 499 541
|
||||||
|
#
|
||||||
|
name: Heat_lo
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 8512 4215 571 1512 570 497 599 442 598 443 597 1486 580 461 568 473 567 474 567 475 567 474 566 475 566 474 567 474 567 1516 566 475 567 474 566 1517 566 474 567 475 567 474 566 475 566 1516 566 474 567 1517 566 475 567 474 566 475 566 1518 566
|
||||||
|
#
|
||||||
|
name: Heat_hi
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 8514 4239 546 1536 546 495 546 494 546 495 546 1538 570 471 544 497 543 498 543 500 542 499 542 500 542 499 542 499 542 1541 541 501 541 499 541 1542 541 1543 540 1566 517 1567 517 524 517 1566 517 524 517 1567 516 1566 516 525 517 524 517 524 517
|
||||||
#
|
#
|
||||||
# Model: Shivaki SSA18002
|
# Model: Shivaki SSA18002
|
||||||
name: Off
|
name: Off
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Filetype: IR library file
|
Filetype: IR library file
|
||||||
Version: 1
|
Version: 1
|
||||||
# Last Updated 24th Jul, 2023
|
# Last Updated 24th Jul, 2023
|
||||||
# Last Checked 24th Jul, 2023
|
# Last Checked 5th Aug, 2023
|
||||||
#
|
#
|
||||||
name: Power
|
name: Power
|
||||||
type: parsed
|
type: parsed
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Filetype: IR library file
|
Filetype: IR library file
|
||||||
Version: 1
|
Version: 1
|
||||||
# Last Updated 24th Jul, 2023
|
# Last Updated 5th Aug, 2023
|
||||||
# Last Checked 24th Jul, 2023
|
# Last Checked 5th Aug, 2023
|
||||||
#
|
#
|
||||||
name: Power
|
name: Power
|
||||||
type: raw
|
type: raw
|
||||||
@@ -1911,3 +1911,27 @@ type: raw
|
|||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.330000
|
duty_cycle: 0.330000
|
||||||
data: 1253 434 1258 435 492 1200 1258 438 1258 434 498 1194 494 1202 1257 433 494 1200 493 1200 493 1200 493 7940 1259 434 1258 433 493 1200 1259 438 1258 433 493 1199 494 1200 1259 434 492 1200 493 1200 493 1199 494 7939 1258 435 1257 434 497 1196 1258 437 1259 433 498 1196 492 1201 1258 434 497 1197 491 1200 493 1201 492 7941 1258 434 1258 435 495 1197 1258 437 1259 433 497 1197 497 1196 1259 434 496 1197 496 1197 496 1196 497 7939 1258 435 1257 434 495 1198 1258 438 1258 434 495 1198 495 1199 1257 435 494 1199 494 1197 496 1197 496
|
data: 1253 434 1258 435 492 1200 1258 438 1258 434 498 1194 494 1202 1257 433 494 1200 493 1200 493 1200 493 7940 1259 434 1258 433 493 1200 1259 438 1258 433 493 1199 494 1200 1259 434 492 1200 493 1200 493 1199 494 7939 1258 435 1257 434 497 1196 1258 437 1259 433 498 1196 492 1201 1258 434 497 1197 491 1200 493 1201 492 7941 1258 434 1258 435 495 1197 1258 437 1259 433 497 1197 497 1196 1259 434 496 1197 496 1197 496 1196 497 7939 1258 435 1257 434 495 1198 1258 438 1258 434 495 1198 495 1199 1257 435 494 1199 494 1197 496 1197 496
|
||||||
|
#
|
||||||
|
name: Power
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.33
|
||||||
|
data: 121 20917 311 387 1345 372 1316 372 450 1212 1319 400 1292 396 450 1210 479 1212 476 1238 450 1238 451 1238 451 1238 1345 7078 1316 372 1315 372 474 1216 1314 377 1314 374 472 1217 472 1217 472 1217 472 1217 472 1217 472 1217 1314 7106 1314 375 1313 374 472 1218 1313 378 1314 375 471 1218 471 1218 471 1218 471 1218 471 1218 471 1218 1313 7108 1312 376 1312 375 471 1219 1312 380 1312 376 470 1218 471 1218 471 1219 470 1218 471 1219 470 1219 1312 7110 1311 376 1312 376 470 1219 1312 381 1311 377 469 1219 470 1219 469 1220 469 1220 469 1220 469 1221 1310 7133 1286 402 1286 401 445 1245 1285 406 1286 401 445 1244 444 1244 445 1244 445 1244 445 1244 445 1245 1286 7134 1285 402 1286 402 444 1245 1286 406 1286 402 444 1245 444 1245 444 1245 444 1245 443 1245 444 1245 1285 7136 1284 403 1285 403 443 1245 1285 407 1285 403 443 1246 443 1246 443 1246 443 1246 443 1246 443 1246 1285 7135 1284 404 1284 404 442 1247 1284 408 1284 404 442 1247 442 1247 442 1247 442 1247 442 1248 441 1248 1283 7138 1282 405 1283 405 441 1249 1282 410 1281 407 440 1250 439 1249 440 1273 415 1274 390 1299 415 1274 1256 7166 1256 432 1256 431 415 1275 1255 436 1232 456 390 1299 415 1275 390 1299 390 1299 390 1299 390 1300 1231 7189 1231 457 1232 457 389 1301 1230 461 1231 458 388 1301 388 1301 388 1301 388 1326 363 1326 363 1327 1204 7217 1204 484 1205 484 362 1328 1203 488 1204 485 361 1328 361 1328 361 1328 361 1329 360 1353 335 1330 1202 7246 1177 511 1177 512 334 1356 1175 542 1150 539 307 1383 306 1383 306 1382 307 1409 280 1409 280 1410 1122
|
||||||
|
#
|
||||||
|
name: Rotate
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.33
|
||||||
|
data: 1293 396 1293 395 450 1238 1294 399 1293 395 450 1238 451 1238 1294 395 450 1237 452 1237 452 1237 452 7964 1294 395 1318 370 475 1215 1316 377 1315 397 448 1241 448 1242 1290 398 447 1242 447 1242 447 1242 447 7970 1290 398 1292 372 473 1217 1316 377 1315 397 448 1217 473 1217 1316 372 473 1216 473 1217 473 1216 473 7944 1316 373 1316 372 473 1217 1316 376 1316 372 473 1216 473 1217 1316 372 473 1216 473 1216 473 1216 473 7942 1318 372 1317 371 474 1216 1317 375 1317 371 473 1216 473 1216 1318 371 474 1216 473 1216 473 1216 473 7943 1318 371 1318 371 474 1216 1318 375 1317 371 474 1216 474 1216 1318 371 474 1216 473 1216 473 1216 474 7943 1317 372 1317 372 473 1217 1317 376 1316 372 473 1217 472 1217 1316 372 473 1217 472 1217 472 1217 472 7944 1314 375 1314 398 447 1243 1290 403 1289 398 447 1243 446 1244 1289 399 446 1243 447 1243 446 1243 446 7971 1289 400 1289 399 446 1244 1289 403 1289 399 446 1243 446 1244 1289 399 446 1244 446 1244 445 1244 445 7972 1288 400 1289 399 446 1244 1290 403 1289 399 446 1244 445 1244 1289 399 446 1244 446 1244 445 1244 445 7946 1288 401 1288 400 469 1222 1311 380 1312 399 445 1244 445 1245 1289 399 445 1244 445 1245 445 1244 446 7971 1289 400 1289 400 444 1246 1289 403 1289 400 443 1246 444 1245 1272 416 445 1244 420 1269 444 1245 420 7996 1288 401 1288 400 420 1270 1264 429 1263 425 419 1270 419 1270 1264 425 419 1270 419 1270 419 1270 419 7995 1262 426 1263 425 419 1270 1263 430 1262 425 419 1270 419 1271 1262 426 418 1271 418 1271 418 1271 418
|
||||||
|
#
|
||||||
|
name: Timer
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.33
|
||||||
|
data: 1321 393 1295 393 451 1211 1322 396 1295 393 451 1210 507 1182 507 1181 1351 364 479 1208 480 1208 480 7933 1322 366 1320 368 475 1213 1319 373 1318 370 474 1214 474 1215 474 1215 1317 371 473 1215 473 1215 473 7939 1315 372 1316 372 472 1216 1316 376 1315 373 471 1217 472 1218 470 1218 1313 398 446 1242 446 1242 446 7967 1262 425 1263 425 444 1245 1263 429 1287 400 445 1244 445 1243 446 1244 1288 400 445 1243 446 1243 446 7966 1288 400 1288 400 445 1244 1287 404 1288 400 445 1244 444 1244 444 1245 1286 401 444 1244 444 1245 444 7968 1261 426 1286 401 419 1270 1285 406 1285 402 444 1244 445 1244 445 1245 1287 400 444 1244 445 1244 444 7968 1288 400 1288 400 444 1244 1288 404 1287 399 445 1244 444 1244 445 1244 1263 425 444 1244 444 1244 444 7967 1261 427 1261 426 418 1272 1260 456 1235 452 392 1296 392 1296 393 1297 1235 453 392 1296 393 1296 393 7996 1261 427 1261 427 418 1270 1262 430 1285 402 444 1245 443 1245 444 1245 1286 402 444 1245 444 1245 444 7969 1286 402 1286 402 444 1245 1286 406 1285 402 444 1245 444 1245 444 1245 1286 402 444 1245 444 1245 444 7968 1284 403 1285 403 443 1246 1284 407 1284 403 443 1246 442 1246 443 1246 1284 403 443 1246 443 1246 442 7971 1284 405 1283 405 441 1247 1283 408 1283 405 441 1248 441 1248 440 1249 1281 406 440 1249 440 1249 440 7974 1281 408 1280 431 390 1299 1232 460 1256 432 389 1299 390 1299 389 1300 1231 456 390 1299 390 1299 390 8023 1231 457 1231 457 389 1300 1231 461 1230 458 388 1300 389 1301 388 1301 1230 458 388 1302 387 1301 388 8027 1228 484 1204 484 362 1327 1204 488 1203 484 362 1328 361 1328 361 1329 1202 486 360 1354 335 1329 360 8080 1176 512 1176 512 334 1356 1175 542 1149 539 306 1382 307 1384 305 1383 1149 566 279 1436 252 1410 279
|
||||||
|
#
|
||||||
|
name: Mode
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.33
|
||||||
|
data: 1373 341 1295 393 452 1211 1322 397 1295 393 451 1210 479 1210 479 1211 478 1237 1296 393 451 1236 453 7962 1321 367 1320 368 476 1214 1318 374 1318 370 474 1215 474 1215 474 1215 474 1216 1316 371 473 1215 474 7941 1316 372 1316 372 472 1217 1316 376 1316 372 473 1216 473 1216 473 1217 472 1217 1315 373 472 1217 472 7941 1315 374 1314 374 471 1218 1314 401 1291 398 447 1242 447 1242 447 1242 447 1243 1290 398 446 1242 447 7968 1290 399 1289 398 447 1243 1290 402 1290 398 447 1242 447 1242 447 1242 447 1243 1289 398 446 1243 446 7968 1289 399 1289 398 447 1243 1290 402 1290 398 446 1243 446 1243 446 1243 446 1243 1290 398 446 1243 446 7967 1289 399 1289 399 446 1244 1289 403 1289 398 446 1243 446 1243 446 1243 446 1244 1289 399 446 1243 446 7969 1288 400 1288 399 445 1244 1288 403 1288 400 445 1244 445 1244 445 1244 445 1244 1288 400 445 1244 420 7995 1261 427 1261 428 416 1296 1236 456 1236 452 392 1296 393 1296 393 1296 393 1296 1236 452 393 1296 393 7997 1260 428 1260 428 416 1273 1260 432 1259 428 417 1296 392 1272 417 1296 393 1296 1237 452 393 1296 393 8021 1236 452 1236 452 392 1297 1236 456 1236 452 393 1297 392 1297 392 1297 392 1298 1235 453 391 1298 391
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Filetype: IR library file
|
Filetype: IR library file
|
||||||
Version: 1
|
Version: 1
|
||||||
# Last Updated 24th Jul, 2023
|
# Last Updated 24th Jul, 2023
|
||||||
# Last Checked 24th Jul, 2023
|
# Last Checked 5th Aug, 2023
|
||||||
#
|
#
|
||||||
# ON
|
# ON
|
||||||
name: Power
|
name: Power
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Filetype: IR library file
|
Filetype: IR library file
|
||||||
Version: 1
|
Version: 1
|
||||||
# Last Updated 24th Jul, 2023
|
# Last Updated 24th Jul, 2023
|
||||||
# Last Checked 24th Jul, 2023
|
# Last Checked 5th Aug, 2023
|
||||||
#
|
#
|
||||||
name: Power
|
name: Power
|
||||||
type: parsed
|
type: parsed
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <toolbox/manchester_decoder.h>
|
#include <toolbox/manchester_decoder.h>
|
||||||
#include <lfrfid/tools/bit_lib.h>
|
#include <lfrfid/tools/bit_lib.h>
|
||||||
#include "lfrfid_protocols.h"
|
#include "lfrfid_protocols.h"
|
||||||
|
#include <furi_hal_rtc.h>
|
||||||
|
|
||||||
#define FDX_B_ENCODED_BIT_SIZE (128)
|
#define FDX_B_ENCODED_BIT_SIZE (128)
|
||||||
#define FDX_B_ENCODED_BYTE_SIZE (((FDX_B_ENCODED_BIT_SIZE) / 8))
|
#define FDX_B_ENCODED_BYTE_SIZE (((FDX_B_ENCODED_BIT_SIZE) / 8))
|
||||||
@@ -323,8 +324,12 @@ void protocol_fdx_b_render_brief_data(ProtocolFDXB* protocol, FuriString* result
|
|||||||
|
|
||||||
float temperature;
|
float temperature;
|
||||||
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
|
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
|
||||||
|
if(furi_hal_rtc_get_locale_units() == FuriHalRtcLocaleUnitsMetric) {
|
||||||
float temperature_c = (temperature - 32) / 1.8;
|
float temperature_c = (temperature - 32) / 1.8;
|
||||||
furi_string_cat_printf(result, "T: %.2fC", (double)temperature_c);
|
furi_string_cat_printf(result, "T: %.2fC", (double)temperature_c);
|
||||||
|
} else {
|
||||||
|
furi_string_cat_printf(result, "T: %.2fF", (double)temperature);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
furi_string_cat_printf(result, "T: ---");
|
furi_string_cat_printf(result, "T: ---");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,13 +95,9 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
}
|
}
|
||||||
} else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
} else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
||||||
nfc_worker_emulate_uid(nfc_worker);
|
nfc_worker_emulate_uid(nfc_worker);
|
||||||
}
|
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
#if FURI_DEBUG
|
|
||||||
else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
|
||||||
nfc_worker_emulate_apdu(nfc_worker);
|
nfc_worker_emulate_apdu(nfc_worker);
|
||||||
}
|
} else if(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
|
||||||
#endif
|
|
||||||
else if(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
|
|
||||||
nfc_worker_emulate_mf_ultralight(nfc_worker);
|
nfc_worker_emulate_mf_ultralight(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
|
} else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
|
||||||
nfc_worker_emulate_mf_classic(nfc_worker);
|
nfc_worker_emulate_mf_classic(nfc_worker);
|
||||||
@@ -755,7 +751,7 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if FURI_DEBUG
|
|
||||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
FuriHalNfcDevData params = {
|
FuriHalNfcDevData params = {
|
||||||
@@ -788,7 +784,6 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
|||||||
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void nfc_worker_mf_ultralight_auth_received_callback(MfUltralightAuth auth, void* context) {
|
void nfc_worker_mf_ultralight_auth_received_callback(MfUltralightAuth auth, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const PDOLValue* const pdol_values[] = {
|
|||||||
&pdol_transaction_cert,
|
&pdol_transaction_cert,
|
||||||
&pdol_unpredict_number,
|
&pdol_unpredict_number,
|
||||||
};
|
};
|
||||||
#if FURI_DEBUG
|
|
||||||
static const uint8_t select_ppse_ans[] = {0x6F, 0x29, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59, 0x2E,
|
static const uint8_t select_ppse_ans[] = {0x6F, 0x29, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59, 0x2E,
|
||||||
0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31,
|
0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31,
|
||||||
0xA5, 0x17, 0xBF, 0x0C, 0x14, 0x61, 0x12, 0x4F, 0x07,
|
0xA5, 0x17, 0xBF, 0x0C, 0x14, 0x61, 0x12, 0x4F, 0x07,
|
||||||
@@ -61,7 +61,7 @@ static const uint8_t pdol_ans[] = {0x77, 0x40, 0x82, 0x02, 0x20, 0x00, 0x57, 0x1
|
|||||||
0x00, 0x9F, 0x26, 0x08, 0x7A, 0x65, 0x7F, 0xD3, 0x52, 0x96,
|
0x00, 0x9F, 0x26, 0x08, 0x7A, 0x65, 0x7F, 0xD3, 0x52, 0x96,
|
||||||
0xC9, 0x85, 0x9F, 0x27, 0x01, 0x00, 0x9F, 0x36, 0x02, 0x06,
|
0xC9, 0x85, 0x9F, 0x27, 0x01, 0x00, 0x9F, 0x36, 0x02, 0x06,
|
||||||
0x0C, 0x9F, 0x6C, 0x02, 0x10, 0x00, 0x90, 0x00};
|
0x0C, 0x9F, 0x6C, 0x02, 0x10, 0x00, 0x90, 0x00};
|
||||||
#endif
|
|
||||||
static void emv_trace(FuriHalNfcTxRxContext* tx_rx, const char* message) {
|
static void emv_trace(FuriHalNfcTxRxContext* tx_rx, const char* message) {
|
||||||
if(furi_log_get_level() == FuriLogLevelTrace) {
|
if(furi_log_get_level() == FuriLogLevelTrace) {
|
||||||
FURI_LOG_T(TAG, "%s", message);
|
FURI_LOG_T(TAG, "%s", message);
|
||||||
@@ -409,7 +409,6 @@ bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
|
|||||||
return card_num_read;
|
return card_num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FURI_DEBUG
|
|
||||||
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
|
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
|
||||||
furi_assert(tx_rx);
|
furi_assert(tx_rx);
|
||||||
bool emulation_complete = false;
|
bool emulation_complete = false;
|
||||||
@@ -443,4 +442,3 @@ bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
|
|||||||
|
|
||||||
return emulation_complete;
|
return emulation_complete;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user