mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
3
applications/external/totp/application.fam
vendored
3
applications/external/totp/application.fam
vendored
@@ -27,9 +27,6 @@ App(
|
||||
Lib(
|
||||
name="base64",
|
||||
),
|
||||
Lib(
|
||||
name="linked_list"
|
||||
),
|
||||
Lib(
|
||||
name="timezone_utils",
|
||||
),
|
||||
|
||||
2
applications/external/totp/cli/cli.c
vendored
2
applications/external/totp/cli/cli.c
vendored
@@ -63,7 +63,7 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
|
||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
|
||||
totp_cli_command_automation_handle(plugin_state, args, cli);
|
||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
|
||||
totp_cli_command_reset_handle(cli, cli_context->event_queue);
|
||||
totp_cli_command_reset_handle(plugin_state, cli, cli_context->event_queue);
|
||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
|
||||
totp_cli_command_update_handle(plugin_state, args, cli);
|
||||
} else if(
|
||||
|
||||
42
applications/external/totp/cli/cli_helpers.c
vendored
42
applications/external/totp/cli/cli_helpers.c
vendored
@@ -3,6 +3,11 @@
|
||||
#include <lib/toolbox/args.h>
|
||||
#include "../types/plugin_event.h"
|
||||
|
||||
const char* TOTP_CLI_COLOR_ERROR = "91m";
|
||||
const char* TOTP_CLI_COLOR_WARNING = "93m";
|
||||
const char* TOTP_CLI_COLOR_SUCCESS = "92m";
|
||||
const char* TOTP_CLI_COLOR_INFO = "96m";
|
||||
|
||||
bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) {
|
||||
if(plugin_state->current_scene == TotpSceneAuthentication) {
|
||||
TOTP_CLI_PRINTF("Pleases enter PIN on your flipper device\r\n");
|
||||
@@ -13,10 +18,11 @@ bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) {
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
totp_cli_delete_last_line();
|
||||
|
||||
if(plugin_state->current_scene == TotpSceneAuthentication || //-V560
|
||||
plugin_state->current_scene == TotpSceneNone) { //-V560
|
||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +60,7 @@ bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input) {
|
||||
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
|
||||
size_t out_str_size = furi_string_size(out_str);
|
||||
if(out_str_size > 0) {
|
||||
TOTP_CLI_DELETE_LAST_CHAR();
|
||||
totp_cli_delete_last_char();
|
||||
furi_string_left(out_str, out_str_size - 1);
|
||||
}
|
||||
} else if(c == CliSymbolAsciiCR) {
|
||||
@@ -83,3 +89,35 @@ void furi_string_secure_free(FuriString* str) {
|
||||
|
||||
furi_string_free(str);
|
||||
}
|
||||
|
||||
void totp_cli_print_invalid_arguments() {
|
||||
TOTP_CLI_PRINTF_ERROR(
|
||||
"Invalid command arguments. use \"help\" command to get list of available commands");
|
||||
}
|
||||
|
||||
void totp_cli_print_error_updating_config_file() {
|
||||
TOTP_CLI_PRINTF_ERROR("An error has occurred during updating config file\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_print_error_loading_token_info() {
|
||||
TOTP_CLI_PRINTF_ERROR("An error has occurred during loading token information\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_print_processing() {
|
||||
TOTP_CLI_PRINTF("Processing, please wait...\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_delete_last_char() {
|
||||
TOTP_CLI_PRINTF("\b \b");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void totp_cli_delete_current_line() {
|
||||
TOTP_CLI_PRINTF("\33[2K\r");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void totp_cli_delete_last_line() {
|
||||
TOTP_CLI_PRINTF("\033[A\33[2K\r");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
67
applications/external/totp/cli/cli_helpers.h
vendored
67
applications/external/totp/cli/cli_helpers.h
vendored
@@ -14,6 +14,11 @@
|
||||
#define DOCOPT_OPTIONS "[options]"
|
||||
#define DOCOPT_DEFAULT(val) "[default: " val "]"
|
||||
|
||||
extern const char* TOTP_CLI_COLOR_ERROR;
|
||||
extern const char* TOTP_CLI_COLOR_WARNING;
|
||||
extern const char* TOTP_CLI_COLOR_SUCCESS;
|
||||
extern const char* TOTP_CLI_COLOR_INFO;
|
||||
|
||||
#define TOTP_CLI_PRINTF(format, ...) printf(format, ##__VA_ARGS__)
|
||||
|
||||
#define TOTP_CLI_PRINTF_COLORFUL(color, format, ...) \
|
||||
@@ -22,11 +27,6 @@
|
||||
printf("\e[0m"); \
|
||||
fflush(stdout)
|
||||
|
||||
#define TOTP_CLI_COLOR_ERROR "91m"
|
||||
#define TOTP_CLI_COLOR_WARNING "93m"
|
||||
#define TOTP_CLI_COLOR_SUCCESS "92m"
|
||||
#define TOTP_CLI_COLOR_INFO "96m"
|
||||
|
||||
#define TOTP_CLI_PRINTF_ERROR(format, ...) \
|
||||
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_ERROR, format, ##__VA_ARGS__)
|
||||
#define TOTP_CLI_PRINTF_WARNING(format, ...) \
|
||||
@@ -36,24 +36,12 @@
|
||||
#define TOTP_CLI_PRINTF_INFO(format, ...) \
|
||||
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_INFO, format, ##__VA_ARGS__)
|
||||
|
||||
#define TOTP_CLI_DELETE_LAST_LINE() \
|
||||
TOTP_CLI_PRINTF("\033[A\33[2K\r"); \
|
||||
fflush(stdout)
|
||||
#define TOTP_CLI_LOCK_UI(plugin_state) \
|
||||
Scene __previous_scene = plugin_state->current_scene; \
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneStandby)
|
||||
|
||||
#define TOTP_CLI_DELETE_CURRENT_LINE() \
|
||||
TOTP_CLI_PRINTF("\33[2K\r"); \
|
||||
fflush(stdout)
|
||||
|
||||
#define TOTP_CLI_DELETE_LAST_CHAR() \
|
||||
TOTP_CLI_PRINTF("\b \b"); \
|
||||
fflush(stdout)
|
||||
|
||||
#define TOTP_CLI_PRINT_INVALID_ARGUMENTS() \
|
||||
TOTP_CLI_PRINTF_ERROR( \
|
||||
"Invalid command arguments. use \"help\" command to get list of available commands")
|
||||
|
||||
#define TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE() \
|
||||
TOTP_CLI_PRINTF_ERROR("An error has occurred during updating config file\r\n")
|
||||
#define TOTP_CLI_UNLOCK_UI(plugin_state) \
|
||||
totp_scene_director_activate_scene(plugin_state, __previous_scene)
|
||||
|
||||
/**
|
||||
* @brief Checks whether user is authenticated and entered correct PIN.
|
||||
@@ -92,3 +80,38 @@ bool args_read_uint8_and_trim(FuriString* args, uint8_t* value);
|
||||
* @param str instance to free
|
||||
*/
|
||||
void furi_string_secure_free(FuriString* str);
|
||||
|
||||
/**
|
||||
* @brief Deletes last printed line in console
|
||||
*/
|
||||
void totp_cli_delete_last_line();
|
||||
|
||||
/**
|
||||
* @brief Deletes current printed line in console
|
||||
*/
|
||||
void totp_cli_delete_current_line();
|
||||
|
||||
/**
|
||||
* @brief Deletes last printed char in console
|
||||
*/
|
||||
void totp_cli_delete_last_char();
|
||||
|
||||
/**
|
||||
* @brief Prints error message about invalid command arguments
|
||||
*/
|
||||
void totp_cli_print_invalid_arguments();
|
||||
|
||||
/**
|
||||
* @brief Prints error message about config file update error
|
||||
*/
|
||||
void totp_cli_print_error_updating_config_file();
|
||||
|
||||
/**
|
||||
* @brief Prints error message about config file loading error
|
||||
*/
|
||||
void totp_cli_print_error_loading_token_info();
|
||||
|
||||
/**
|
||||
* @brief Prints message to let user knwo that command is processing now
|
||||
*/
|
||||
void totp_cli_print_processing();
|
||||
167
applications/external/totp/cli/commands/add/add.c
vendored
167
applications/external/totp/cli/commands/add/add.c
vendored
@@ -1,7 +1,6 @@
|
||||
#include "add.h"
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../services/convert/convert.h"
|
||||
@@ -9,6 +8,77 @@
|
||||
#include "../../../ui/scene_director.h"
|
||||
#include "../../common_command_arguments.h"
|
||||
|
||||
struct TotpAddContext {
|
||||
FuriString* args;
|
||||
Cli* cli;
|
||||
uint8_t* iv;
|
||||
};
|
||||
|
||||
enum TotpIteratorUpdateTokenResultsEx {
|
||||
TotpIteratorUpdateTokenResultInvalidSecret = 1,
|
||||
TotpIteratorUpdateTokenResultCancelled = 2,
|
||||
TotpIteratorUpdateTokenResultInvalidArguments = 3
|
||||
};
|
||||
|
||||
static TotpIteratorUpdateTokenResult
|
||||
add_token_handler(TokenInfo* token_info, const void* context) {
|
||||
const struct TotpAddContext* context_t = context;
|
||||
|
||||
// Reading token name
|
||||
if(!args_read_probably_quoted_string_and_trim(context_t->args, token_info->name)) {
|
||||
return TotpIteratorUpdateTokenResultInvalidArguments;
|
||||
}
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
// Read optional arguments
|
||||
bool mask_user_input = true;
|
||||
PlainTokenSecretEncoding token_secret_encoding = PlainTokenSecretEncodingBase32;
|
||||
while(args_read_string_and_trim(context_t->args, temp_str)) {
|
||||
bool parsed = false;
|
||||
if(!totp_cli_try_read_algo(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_digits(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_duration(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) &&
|
||||
!totp_cli_try_read_automation_features(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_plain_token_secret_encoding(
|
||||
temp_str, context_t->args, &parsed, &token_secret_encoding)) {
|
||||
totp_cli_printf_unknown_argument(temp_str);
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
furi_string_free(temp_str);
|
||||
return TotpIteratorUpdateTokenResultInvalidArguments;
|
||||
}
|
||||
}
|
||||
|
||||
// Reading token secret
|
||||
furi_string_reset(temp_str);
|
||||
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)) {
|
||||
totp_cli_delete_last_line();
|
||||
furi_string_secure_free(temp_str);
|
||||
return TotpIteratorUpdateTokenResultCancelled;
|
||||
}
|
||||
|
||||
totp_cli_delete_last_line();
|
||||
|
||||
bool secret_set = token_info_set_secret(
|
||||
token_info,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
token_secret_encoding,
|
||||
context_t->iv);
|
||||
|
||||
furi_string_secure_free(temp_str);
|
||||
|
||||
if(!secret_set) {
|
||||
return TotpIteratorUpdateTokenResultInvalidSecret;
|
||||
}
|
||||
|
||||
return TotpIteratorUpdateTokenResultSuccess;
|
||||
}
|
||||
|
||||
void totp_cli_command_add_docopt_commands() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD ", " TOTP_CLI_COMMAND_ADD_ALT
|
||||
", " TOTP_CLI_COMMAND_ADD_ALT2 " Add new token\r\n");
|
||||
@@ -75,90 +145,33 @@ void totp_cli_command_add_docopt_options() {
|
||||
}
|
||||
|
||||
void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
TokenInfo* token_info = token_info_alloc();
|
||||
|
||||
// Reading token name
|
||||
if(!args_read_probably_quoted_string_and_trim(args, temp_str)) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
furi_string_free(temp_str);
|
||||
token_info_free(token_info);
|
||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t temp_cstr_len = furi_string_size(temp_str);
|
||||
token_info->name = malloc(temp_cstr_len + 1);
|
||||
furi_check(token_info->name != NULL);
|
||||
strlcpy(token_info->name, furi_string_get_cstr(temp_str), temp_cstr_len + 1);
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
|
||||
// Read optional arguments
|
||||
bool mask_user_input = true;
|
||||
PlainTokenSecretEncoding token_secret_encoding = PLAIN_TOKEN_ENCODING_BASE32;
|
||||
while(args_read_string_and_trim(args, temp_str)) {
|
||||
bool parsed = false;
|
||||
if(!totp_cli_try_read_algo(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_digits(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_duration(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) &&
|
||||
!totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_plain_token_secret_encoding(
|
||||
temp_str, args, &parsed, &token_secret_encoding)) {
|
||||
totp_cli_printf_unknown_argument(temp_str);
|
||||
}
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
if(!parsed) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
furi_string_free(temp_str);
|
||||
token_info_free(token_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
struct TotpAddContext add_context = {.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
||||
TotpIteratorUpdateTokenResult add_result =
|
||||
totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
|
||||
|
||||
// Reading token secret
|
||||
furi_string_reset(temp_str);
|
||||
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
|
||||
if(!totp_cli_read_line(cli, temp_str, mask_user_input) ||
|
||||
!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
if(add_result == TotpIteratorUpdateTokenResultSuccess) {
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully added\r\n",
|
||||
furi_string_get_cstr(
|
||||
totp_token_info_iterator_get_current_token(iterator_context)->name));
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultCancelled) {
|
||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||
furi_string_secure_free(temp_str);
|
||||
token_info_free(token_info);
|
||||
return;
|
||||
}
|
||||
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
|
||||
bool load_generate_token_scene = false;
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
load_generate_token_scene = true;
|
||||
}
|
||||
|
||||
bool secret_set = token_info_set_secret(
|
||||
token_info,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
token_secret_encoding,
|
||||
plugin_state->iv);
|
||||
|
||||
furi_string_secure_free(temp_str);
|
||||
|
||||
if(secret_set) {
|
||||
TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, token_info, furi_check);
|
||||
plugin_state->tokens_count++;
|
||||
|
||||
if(totp_config_file_save_new_token(token_info) == TotpConfigFileUpdateSuccess) {
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully added\r\n", token_info->name);
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
}
|
||||
} else {
|
||||
token_info_free(token_info);
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultInvalidArguments) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultInvalidSecret) {
|
||||
TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n");
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultFileUpdateFailed) {
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
if(load_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ void totp_cli_command_automation_docopt_arguments() {
|
||||
"\r\n");
|
||||
}
|
||||
|
||||
static void totp_cli_command_automation_print_method(AutomationMethod method, char* color) {
|
||||
static void totp_cli_command_automation_print_method(AutomationMethod method, const char* color) {
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
bool has_previous_method = false;
|
||||
#endif
|
||||
@@ -88,26 +88,20 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
||||
|
||||
do {
|
||||
if(!args_valid) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
totp_cli_print_invalid_arguments();
|
||||
break;
|
||||
}
|
||||
|
||||
if(new_method_provided) {
|
||||
Scene previous_scene = TotpSceneNone;
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken ||
|
||||
plugin_state->current_scene == TotpSceneAppSettings) {
|
||||
previous_scene = plugin_state->current_scene;
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
}
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
plugin_state->automation_method = new_method;
|
||||
if(totp_config_file_update_automation_method(new_method) ==
|
||||
TotpConfigFileUpdateSuccess) {
|
||||
if(totp_config_file_update_automation_method(plugin_state)) {
|
||||
TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
|
||||
totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
||||
cli_nl();
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
@@ -118,9 +112,7 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
||||
}
|
||||
#endif
|
||||
|
||||
if(previous_scene != TotpSceneNone) {
|
||||
totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
|
||||
}
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_INFO("Current automation method is ");
|
||||
totp_cli_command_automation_print_method(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../../ui/scene_director.h"
|
||||
@@ -37,10 +36,13 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
||||
return;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
|
||||
int token_number;
|
||||
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||
token_number > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,23 +53,27 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
||||
confirm_needed = false;
|
||||
} else {
|
||||
totp_cli_printf_unknown_argument(temp_str);
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
totp_cli_print_invalid_arguments();
|
||||
furi_string_free(temp_str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
furi_string_free(temp_str);
|
||||
|
||||
ListNode* list_node = list_element_at(plugin_state->tokens_list, token_number - 1);
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
TokenInfo* token_info = list_node->data;
|
||||
size_t original_token_index =
|
||||
totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
totp_token_info_iterator_go_to(iterator_context, token_number - 1);
|
||||
const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context);
|
||||
const char* token_info_name = furi_string_get_cstr(token_info->name);
|
||||
|
||||
bool confirmed = !confirm_needed;
|
||||
if(confirm_needed) {
|
||||
TOTP_CLI_PRINTF_WARNING("WARNING!\r\n");
|
||||
TOTP_CLI_PRINTF_WARNING(
|
||||
"TOKEN \"%s\" WILL BE PERMANENTLY DELETED WITHOUT ABILITY TO RECOVER IT.\r\n",
|
||||
token_info->name);
|
||||
token_info_name);
|
||||
TOTP_CLI_PRINTF_WARNING("Confirm? [y/n]\r\n");
|
||||
fflush(stdout);
|
||||
char user_pick;
|
||||
@@ -80,32 +86,21 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
||||
}
|
||||
|
||||
if(confirmed) {
|
||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool activate_generate_token_scene = false;
|
||||
if(plugin_state->current_scene != TotpSceneAuthentication) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
activate_generate_token_scene = true;
|
||||
}
|
||||
|
||||
plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node);
|
||||
plugin_state->tokens_count--;
|
||||
|
||||
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
|
||||
totp_cli_print_processing();
|
||||
if(totp_token_info_iterator_remove_current_token_info(iterator_context)) {
|
||||
totp_cli_delete_last_line();
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully deleted\r\n", token_info->name);
|
||||
"Token \"%s\" has been successfully deleted\r\n", token_info_name);
|
||||
totp_token_info_iterator_go_to(iterator_context, 0);
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
}
|
||||
|
||||
token_info_free(token_info);
|
||||
|
||||
if(activate_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
totp_cli_delete_last_line();
|
||||
totp_cli_print_error_updating_config_file();
|
||||
totp_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||
}
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_INFO("User has not confirmed\r\n");
|
||||
totp_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||
}
|
||||
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "details.h"
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../services/config/constants.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../ui/scene_director.h"
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../common_command_arguments.h"
|
||||
|
||||
@@ -17,21 +18,21 @@
|
||||
} while(false)
|
||||
|
||||
static void print_automation_features(const TokenInfo* token_info) {
|
||||
if(token_info->automation_features == TOKEN_AUTOMATION_FEATURE_NONE) {
|
||||
if(token_info->automation_features == TokenAutomationFeatureNone) {
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", "Automation features", "None");
|
||||
return;
|
||||
}
|
||||
|
||||
bool header_printed = false;
|
||||
if(token_info->automation_features & TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END) {
|
||||
if(token_info->automation_features & TokenAutomationFeatureEnterAtTheEnd) {
|
||||
TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type <Enter> key at the end", header_printed);
|
||||
}
|
||||
|
||||
if(token_info->automation_features & TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END) {
|
||||
if(token_info->automation_features & TokenAutomationFeatureTabAtTheEnd) {
|
||||
TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type <Tab> key at the end", header_printed);
|
||||
}
|
||||
|
||||
if(token_info->automation_features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
|
||||
if(token_info->automation_features & TokenAutomationFeatureTypeSlower) {
|
||||
TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type slower", header_printed);
|
||||
}
|
||||
}
|
||||
@@ -53,26 +54,39 @@ void totp_cli_command_details_handle(PluginState* plugin_state, FuriString* args
|
||||
}
|
||||
|
||||
int token_number;
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||
token_number > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
return;
|
||||
}
|
||||
|
||||
ListNode* list_node = list_element_at(plugin_state->tokens_list, token_number - 1);
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
TokenInfo* token_info = list_node->data;
|
||||
size_t original_token_index =
|
||||
totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
if(totp_token_info_iterator_go_to(iterator_context, token_number - 1)) {
|
||||
const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context);
|
||||
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value");
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28d |\r\n", "Index", token_number);
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", "Name", token_info->name);
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-20s | %-28s |\r\n", "Hashing algorithm", token_info_get_algo_as_cstr(token_info));
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", "Number of digits", token_info->digits);
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-20s | %" PRIu8 " sec.%-21s |\r\n", "Token lifetime", token_info->duration, " ");
|
||||
print_automation_features(token_info);
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value");
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28d |\r\n", "Index", token_number);
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-20s | %-28.28s |\r\n", "Name", furi_string_get_cstr(token_info->name));
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-20s | %-28s |\r\n", "Hashing algorithm", token_info_get_algo_as_cstr(token_info));
|
||||
TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", "Number of digits", token_info->digits);
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-20s | %" PRIu8 " sec.%-21s |\r\n", "Token lifetime", token_info->duration, " ");
|
||||
print_automation_features(token_info);
|
||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||
} else {
|
||||
totp_cli_print_error_loading_token_info();
|
||||
}
|
||||
|
||||
totp_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "list.h"
|
||||
#include <stdlib.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../services/config/constants.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../ui/scene_director.h"
|
||||
#include "../../cli_helpers.h"
|
||||
|
||||
void totp_cli_command_list_docopt_commands() {
|
||||
@@ -20,25 +21,36 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(plugin_state->tokens_list == NULL) {
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
size_t total_count = totp_token_info_iterator_get_total_count(iterator_context);
|
||||
if(total_count <= 0) {
|
||||
TOTP_CLI_PRINTF("There are no tokens");
|
||||
return;
|
||||
}
|
||||
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
size_t original_index = totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
|
||||
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
||||
TOTP_CLI_PRINTF("| %-3s | %-25s | %-6s | %-s | %-s |\r\n", "#", "Name", "Algo", "Ln", "Dur");
|
||||
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
||||
uint16_t index = 1;
|
||||
TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
|
||||
TokenInfo* token_info = (TokenInfo*)node->data;
|
||||
for(size_t i = 0; i < total_count; i++) {
|
||||
totp_token_info_iterator_go_to(iterator_context, i);
|
||||
const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context);
|
||||
TOTP_CLI_PRINTF(
|
||||
"| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n",
|
||||
index,
|
||||
token_info->name,
|
||||
i + 1,
|
||||
furi_string_get_cstr(token_info->name),
|
||||
token_info_get_algo_as_cstr(token_info),
|
||||
token_info->digits,
|
||||
token_info->duration);
|
||||
index++;
|
||||
});
|
||||
}
|
||||
|
||||
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
||||
|
||||
totp_token_info_iterator_go_to(iterator_context, original_index);
|
||||
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../cli_helpers.h"
|
||||
@@ -33,42 +32,52 @@ void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, C
|
||||
return;
|
||||
}
|
||||
|
||||
int token_index;
|
||||
if(!args_read_int_and_trim(args, &token_index) || token_index < 1 ||
|
||||
token_index > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
int token_number;
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
size_t total_count = totp_token_info_iterator_get_total_count(iterator_context);
|
||||
if(!args_read_int_and_trim(args, &token_number) || token_number < 1 ||
|
||||
(size_t)token_number > total_count) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
return;
|
||||
}
|
||||
|
||||
int new_token_index = 0;
|
||||
int new_token_number = 0;
|
||||
|
||||
if(!args_read_int_and_trim(args, &new_token_index) || new_token_index < 1 ||
|
||||
new_token_index > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
if(!args_read_int_and_trim(args, &new_token_number) || new_token_number < 1 ||
|
||||
(size_t)new_token_number > total_count) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
return;
|
||||
}
|
||||
|
||||
bool activate_generate_token_scene = false;
|
||||
if(plugin_state->current_scene != TotpSceneAuthentication) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
activate_generate_token_scene = true;
|
||||
if(token_number == new_token_number) {
|
||||
TOTP_CLI_PRINTF_ERROR("New token number matches current token number\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TokenInfo* token_info = NULL;
|
||||
plugin_state->tokens_list =
|
||||
list_remove_at(plugin_state->tokens_list, token_index - 1, (void**)&token_info);
|
||||
furi_check(token_info != NULL);
|
||||
plugin_state->tokens_list =
|
||||
list_insert_at(plugin_state->tokens_list, new_token_index - 1, token_info);
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
|
||||
size_t token_index = token_number - 1;
|
||||
size_t new_token_index = new_token_number - 1;
|
||||
|
||||
size_t original_token_index =
|
||||
totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
|
||||
totp_cli_print_processing();
|
||||
|
||||
if(totp_token_info_iterator_go_to(iterator_context, token_index) &&
|
||||
totp_token_info_iterator_move_current_token_info(iterator_context, new_token_index)) {
|
||||
totp_cli_delete_last_line();
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully updated\r\n", token_info->name);
|
||||
"Token \"%s\" has been successfully updated\r\n",
|
||||
furi_string_get_cstr(
|
||||
totp_token_info_iterator_get_current_token(iterator_context)->name));
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
totp_cli_delete_last_line();
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
if(activate_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
totp_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -28,7 +28,8 @@ void totp_cli_command_notification_docopt_arguments() {
|
||||
", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "\r\n");
|
||||
}
|
||||
|
||||
static void totp_cli_command_notification_print_method(NotificationMethod method, char* color) {
|
||||
static void
|
||||
totp_cli_command_notification_print_method(NotificationMethod method, const char* color) {
|
||||
bool has_previous_method = false;
|
||||
if(method & NotificationMethodSound) {
|
||||
TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "\"");
|
||||
@@ -73,31 +74,23 @@ void totp_cli_command_notification_handle(PluginState* plugin_state, FuriString*
|
||||
|
||||
do {
|
||||
if(!args_valid) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
totp_cli_print_invalid_arguments();
|
||||
break;
|
||||
}
|
||||
|
||||
if(new_method_provided) {
|
||||
Scene previous_scene = TotpSceneNone;
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken ||
|
||||
plugin_state->current_scene == TotpSceneAppSettings) {
|
||||
previous_scene = plugin_state->current_scene;
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
}
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
plugin_state->notification_method = new_method;
|
||||
if(totp_config_file_update_notification_method(new_method) ==
|
||||
TotpConfigFileUpdateSuccess) {
|
||||
if(totp_config_file_update_notification_method(plugin_state)) {
|
||||
TOTP_CLI_PRINTF_SUCCESS("Notification method is set to ");
|
||||
totp_cli_command_notification_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
||||
cli_nl();
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
if(previous_scene != TotpSceneNone) {
|
||||
totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
|
||||
}
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_INFO("Current notification method is ");
|
||||
totp_cli_command_notification_print_method(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../types/user_pin_codes.h"
|
||||
#include "../../../services/config/config.h"
|
||||
@@ -65,14 +64,14 @@ static bool totp_cli_read_pin(Cli* cli, uint8_t* pin, uint8_t* pin_length) {
|
||||
}
|
||||
}
|
||||
} else if(c == CliSymbolAsciiETX) {
|
||||
TOTP_CLI_DELETE_CURRENT_LINE();
|
||||
totp_cli_delete_current_line();
|
||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||
return false;
|
||||
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
|
||||
if(*pin_length > 0) {
|
||||
*pin_length = *pin_length - 1;
|
||||
pin[*pin_length] = 0;
|
||||
TOTP_CLI_DELETE_LAST_CHAR();
|
||||
totp_cli_delete_last_char();
|
||||
}
|
||||
} else if(c == CliSymbolAsciiCR) {
|
||||
cli_nl();
|
||||
@@ -80,7 +79,7 @@ static bool totp_cli_read_pin(Cli* cli, uint8_t* pin, uint8_t* pin_length) {
|
||||
}
|
||||
}
|
||||
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
totp_cli_delete_last_line();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -97,22 +96,22 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
||||
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
|
||||
do_remove = true;
|
||||
} else {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
totp_cli_print_invalid_arguments();
|
||||
}
|
||||
} else {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
totp_cli_print_invalid_arguments();
|
||||
}
|
||||
|
||||
if((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
bool load_generate_token_scene = false;
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
do {
|
||||
uint8_t old_iv[TOTP_IV_SIZE];
|
||||
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
||||
uint8_t new_pin[TOTP_IV_SIZE];
|
||||
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
||||
uint8_t new_pin_length = 0;
|
||||
if(do_change) {
|
||||
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length) ||
|
||||
!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) {
|
||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||
break;
|
||||
}
|
||||
@@ -121,7 +120,7 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
||||
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
||||
}
|
||||
|
||||
char* backup_path = totp_config_file_backup();
|
||||
char* backup_path = totp_config_file_backup(plugin_state);
|
||||
if(backup_path != NULL) {
|
||||
TOTP_CLI_PRINTF_WARNING("Backup conf file %s has been created\r\n", backup_path);
|
||||
TOTP_CLI_PRINTF_WARNING(
|
||||
@@ -134,61 +133,28 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
||||
break;
|
||||
}
|
||||
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
load_generate_token_scene = true;
|
||||
}
|
||||
TOTP_CLI_PRINTF("Encrypting...\r\n");
|
||||
|
||||
TOTP_CLI_PRINTF("Encrypting, please wait...\r\n");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(!totp_crypto_seed_iv(
|
||||
plugin_state, new_pin_length > 0 ? &new_pin[0] : NULL, new_pin_length)) {
|
||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
break;
|
||||
}
|
||||
bool update_result =
|
||||
totp_config_file_update_encryption(plugin_state, new_pin, new_pin_length);
|
||||
|
||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||
|
||||
TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
|
||||
TokenInfo* token_info = node->data;
|
||||
size_t plain_token_length;
|
||||
uint8_t* plain_token = totp_crypto_decrypt(
|
||||
token_info->token, token_info->token_length, &old_iv[0], &plain_token_length);
|
||||
free(token_info->token);
|
||||
token_info->token = totp_crypto_encrypt(
|
||||
plain_token,
|
||||
plain_token_length,
|
||||
&plugin_state->iv[0],
|
||||
&token_info->token_length);
|
||||
memset_s(plain_token, plain_token_length, 0, plain_token_length);
|
||||
free(plain_token);
|
||||
});
|
||||
totp_cli_delete_last_line();
|
||||
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
|
||||
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
|
||||
if(update_result) {
|
||||
if(do_change) {
|
||||
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully changed\r\n");
|
||||
} else if(do_remove) {
|
||||
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully removed\r\n");
|
||||
}
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
if(load_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
|
||||
furi_string_free(temp_str);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/string.h>
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../../ui/scene_director.h"
|
||||
#include "../../../services/config/config.h"
|
||||
|
||||
#define TOTP_CLI_RESET_CONFIRMATION_KEYWORD "YES"
|
||||
@@ -16,7 +17,11 @@ void totp_cli_command_reset_docopt_usage() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_RESET "\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_reset_handle(Cli* cli, FuriMessageQueue* event_queue) {
|
||||
void totp_cli_command_reset_handle(
|
||||
PluginState* plugin_state,
|
||||
Cli* cli,
|
||||
FuriMessageQueue* event_queue) {
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
TOTP_CLI_PRINTF_WARNING(
|
||||
"As a result of reset all the settings and tokens will be permanently lost.\r\n");
|
||||
TOTP_CLI_PRINTF_WARNING("Do you really want to reset application?\r\n");
|
||||
@@ -27,11 +32,12 @@ void totp_cli_command_reset_handle(Cli* cli, FuriMessageQueue* event_queue) {
|
||||
furi_string_cmpi_str(temp_str, TOTP_CLI_RESET_CONFIRMATION_KEYWORD) == 0;
|
||||
furi_string_free(temp_str);
|
||||
if(is_confirmed) {
|
||||
totp_config_file_reset();
|
||||
totp_config_file_reset(plugin_state);
|
||||
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_force_close_app(event_queue);
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
#define TOTP_CLI_COMMAND_RESET "reset"
|
||||
|
||||
void totp_cli_command_reset_handle(Cli* cli, FuriMessageQueue* event_queue);
|
||||
void totp_cli_command_reset_handle(
|
||||
PluginState* plugin_state,
|
||||
Cli* cli,
|
||||
FuriMessageQueue* event_queue);
|
||||
void totp_cli_command_reset_docopt_commands();
|
||||
void totp_cli_command_reset_docopt_usage();
|
||||
@@ -33,19 +33,14 @@ void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* arg
|
||||
char* strtof_endptr;
|
||||
float tz = strtof(furi_string_get_cstr(temp_str), &strtof_endptr);
|
||||
if(*strtof_endptr == 0 && tz >= -12.75f && tz <= 12.75f) {
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
plugin_state->timezone_offset = tz;
|
||||
if(totp_config_file_update_timezone_offset(tz) == TotpConfigFileUpdateSuccess) {
|
||||
if(totp_config_file_update_timezone_offset(plugin_state)) {
|
||||
TOTP_CLI_PRINTF_SUCCESS("Timezone is set to %f\r\n", (double)tz);
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
}
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
} else if(plugin_state->current_scene == TotpSceneAppSettings) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings, NULL);
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_ERROR("Invalid timezone offset\r\n");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "update.h"
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../services/convert/convert.h"
|
||||
@@ -11,6 +10,103 @@
|
||||
|
||||
#define TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX "-s"
|
||||
|
||||
struct TotpUpdateContext {
|
||||
FuriString* args;
|
||||
Cli* cli;
|
||||
uint8_t* iv;
|
||||
};
|
||||
|
||||
enum TotpIteratorUpdateTokenResultsEx {
|
||||
TotpIteratorUpdateTokenResultInvalidSecret = 1,
|
||||
TotpIteratorUpdateTokenResultCancelled = 2,
|
||||
TotpIteratorUpdateTokenResultInvalidArguments = 3
|
||||
};
|
||||
|
||||
static bool totp_cli_try_read_name(
|
||||
TokenInfo* token_info,
|
||||
const FuriString* arg,
|
||||
FuriString* args,
|
||||
bool* parsed) {
|
||||
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_NAME_PREFIX) == 0) {
|
||||
if(!args_read_probably_quoted_string_and_trim(args, token_info->name) ||
|
||||
furi_string_empty(token_info->name)) {
|
||||
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_NAME_PREFIX);
|
||||
} else {
|
||||
*parsed = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool totp_cli_try_read_change_secret_flag(const FuriString* arg, bool* parsed, bool* flag) {
|
||||
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX) == 0) {
|
||||
*flag = true;
|
||||
*parsed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static TotpIteratorUpdateTokenResult
|
||||
update_token_handler(TokenInfo* token_info, const void* context) {
|
||||
const struct TotpUpdateContext* context_t = context;
|
||||
|
||||
// Read optional arguments
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
bool mask_user_input = true;
|
||||
bool update_token_secret = false;
|
||||
PlainTokenSecretEncoding token_secret_encoding = PlainTokenSecretEncodingBase32;
|
||||
while(args_read_string_and_trim(context_t->args, temp_str)) {
|
||||
bool parsed = false;
|
||||
if(!totp_cli_try_read_name(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_algo(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_digits(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_duration(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) &&
|
||||
!totp_cli_try_read_change_secret_flag(temp_str, &parsed, &update_token_secret) &&
|
||||
!totp_cli_try_read_automation_features(token_info, temp_str, context_t->args, &parsed) &&
|
||||
!totp_cli_try_read_plain_token_secret_encoding(
|
||||
temp_str, context_t->args, &parsed, &token_secret_encoding)) {
|
||||
totp_cli_printf_unknown_argument(temp_str);
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
furi_string_free(temp_str);
|
||||
return TotpIteratorUpdateTokenResultInvalidArguments;
|
||||
}
|
||||
}
|
||||
|
||||
if(update_token_secret) {
|
||||
// Reading token secret
|
||||
furi_string_reset(temp_str);
|
||||
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);
|
||||
totp_cli_delete_last_line();
|
||||
if(!token_secret_read) {
|
||||
furi_string_secure_free(temp_str);
|
||||
return TotpIteratorUpdateTokenResultCancelled;
|
||||
}
|
||||
|
||||
if(!token_info_set_secret(
|
||||
token_info,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
token_secret_encoding,
|
||||
context_t->iv)) {
|
||||
furi_string_secure_free(temp_str);
|
||||
return TotpIteratorUpdateTokenResultInvalidSecret;
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_secure_free(temp_str);
|
||||
|
||||
return TotpIteratorUpdateTokenResultSuccess;
|
||||
}
|
||||
|
||||
void totp_cli_command_update_docopt_commands() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_UPDATE " Update existing token\r\n");
|
||||
}
|
||||
@@ -34,136 +130,46 @@ void totp_cli_command_update_docopt_options() {
|
||||
TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX) " Update token secret\r\n");
|
||||
}
|
||||
|
||||
static bool
|
||||
totp_cli_try_read_name(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed) {
|
||||
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_NAME_PREFIX) == 0) {
|
||||
if(!args_read_probably_quoted_string_and_trim(args, arg) || furi_string_empty(arg)) {
|
||||
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_NAME_PREFIX);
|
||||
} else {
|
||||
if(token_info->name != NULL) {
|
||||
free(token_info->name);
|
||||
}
|
||||
|
||||
size_t temp_cstr_len = furi_string_size(arg);
|
||||
token_info->name = malloc(temp_cstr_len + 1);
|
||||
furi_check(token_info->name != NULL);
|
||||
strlcpy(token_info->name, furi_string_get_cstr(arg), temp_cstr_len + 1);
|
||||
*parsed = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool totp_cli_try_read_change_secret_flag(const FuriString* arg, bool* parsed, bool* flag) {
|
||||
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX) == 0) {
|
||||
*flag = true;
|
||||
*parsed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
|
||||
int token_number;
|
||||
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||
token_number > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
return;
|
||||
}
|
||||
|
||||
ListNode* list_item = list_element_at(plugin_state->tokens_list, token_number - 1);
|
||||
TokenInfo* existing_token_info = list_item->data;
|
||||
TokenInfo* token_info = token_info_clone(existing_token_info);
|
||||
TOTP_CLI_LOCK_UI(plugin_state);
|
||||
|
||||
// Read optional arguments
|
||||
bool mask_user_input = true;
|
||||
bool update_token_secret = false;
|
||||
PlainTokenSecretEncoding token_secret_encoding = PLAIN_TOKEN_ENCODING_BASE32;
|
||||
while(args_read_string_and_trim(args, temp_str)) {
|
||||
bool parsed = false;
|
||||
if(!totp_cli_try_read_name(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_algo(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_digits(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_duration(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) &&
|
||||
!totp_cli_try_read_change_secret_flag(temp_str, &parsed, &update_token_secret) &&
|
||||
!totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed) &&
|
||||
!totp_cli_try_read_plain_token_secret_encoding(
|
||||
temp_str, args, &parsed, &token_secret_encoding)) {
|
||||
totp_cli_printf_unknown_argument(temp_str);
|
||||
}
|
||||
size_t previous_index = totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
totp_token_info_iterator_go_to(iterator_context, token_number - 1);
|
||||
|
||||
if(!parsed) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
furi_string_free(temp_str);
|
||||
token_info_free(token_info);
|
||||
return;
|
||||
}
|
||||
struct TotpUpdateContext update_context = {
|
||||
.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
||||
TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
|
||||
iterator_context, &update_token_handler, &update_context);
|
||||
|
||||
if(update_result == TotpIteratorUpdateTokenResultSuccess) {
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully updated\r\n",
|
||||
furi_string_get_cstr(
|
||||
totp_token_info_iterator_get_current_token(iterator_context)->name));
|
||||
} else if(update_result == TotpIteratorUpdateTokenResultInvalidArguments) {
|
||||
totp_cli_print_invalid_arguments();
|
||||
} else if(update_result == TotpIteratorUpdateTokenResultCancelled) {
|
||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||
} else if(update_result == TotpIteratorUpdateTokenResultInvalidSecret) {
|
||||
TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n");
|
||||
} else if(update_result == TotpIteratorUpdateTokenResultFileUpdateFailed) {
|
||||
totp_cli_print_error_updating_config_file();
|
||||
}
|
||||
|
||||
bool token_secret_read = false;
|
||||
if(update_token_secret) {
|
||||
// Reading token secret
|
||||
furi_string_reset(temp_str);
|
||||
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
|
||||
token_secret_read = totp_cli_read_line(cli, temp_str, mask_user_input);
|
||||
TOTP_CLI_DELETE_LAST_LINE();
|
||||
if(!token_secret_read) {
|
||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool load_generate_token_scene = false;
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
load_generate_token_scene = true;
|
||||
}
|
||||
|
||||
bool token_secret_set = false;
|
||||
if(update_token_secret && token_secret_read) {
|
||||
if(token_info->token != NULL) {
|
||||
free(token_info->token);
|
||||
}
|
||||
token_secret_set = token_info_set_secret(
|
||||
token_info,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
token_secret_encoding,
|
||||
plugin_state->iv);
|
||||
if(!token_secret_set) {
|
||||
TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_secure_free(temp_str);
|
||||
|
||||
if(!update_token_secret || (token_secret_read && token_secret_set)) {
|
||||
list_item->data = token_info;
|
||||
|
||||
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
|
||||
TOTP_CLI_PRINTF_SUCCESS(
|
||||
"Token \"%s\" has been successfully updated\r\n", token_info->name);
|
||||
token_info_free(existing_token_info);
|
||||
} else {
|
||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
||||
list_item->data = existing_token_info;
|
||||
token_info_free(token_info);
|
||||
}
|
||||
} else {
|
||||
token_info_free(token_info);
|
||||
}
|
||||
|
||||
if(load_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
totp_token_info_iterator_go_to(iterator_context, previous_index);
|
||||
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "common_command_arguments.h"
|
||||
#include <lib/toolbox/args.h>
|
||||
|
||||
inline void totp_cli_printf_missed_argument_value(char* arg) {
|
||||
void totp_cli_printf_missed_argument_value(char* arg) {
|
||||
TOTP_CLI_PRINTF_ERROR("Missed or incorrect value for argument \"%s\"\r\n", arg);
|
||||
}
|
||||
|
||||
inline void totp_cli_printf_unknown_argument(const FuriString* arg) {
|
||||
void totp_cli_printf_unknown_argument(const FuriString* arg) {
|
||||
TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(arg));
|
||||
}
|
||||
|
||||
@@ -121,10 +121,10 @@ bool totp_cli_try_read_plain_token_secret_encoding(
|
||||
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX);
|
||||
} else {
|
||||
if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE32_NAME) == 0) {
|
||||
*secret_encoding = PLAIN_TOKEN_ENCODING_BASE32;
|
||||
*secret_encoding = PlainTokenSecretEncodingBase32;
|
||||
*parsed = true;
|
||||
} else if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE64_NAME) == 0) {
|
||||
*secret_encoding = PLAIN_TOKEN_ENCODING_BASE64;
|
||||
*secret_encoding = PlainTokenSecretEncodingBase64;
|
||||
*parsed = true;
|
||||
} else {
|
||||
TOTP_CLI_PRINTF_ERROR(
|
||||
|
||||
@@ -19,23 +19,29 @@
|
||||
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding"
|
||||
|
||||
void totp_cli_printf_unknown_argument(const FuriString* arg);
|
||||
|
||||
void totp_cli_printf_missed_argument_value(char* arg);
|
||||
|
||||
bool totp_cli_try_read_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed);
|
||||
|
||||
bool totp_cli_try_read_digits(
|
||||
TokenInfo* token_info,
|
||||
const FuriString* arg,
|
||||
FuriString* args,
|
||||
bool* parsed);
|
||||
|
||||
bool totp_cli_try_read_duration(
|
||||
TokenInfo* token_info,
|
||||
const FuriString* arg,
|
||||
FuriString* args,
|
||||
bool* parsed);
|
||||
|
||||
bool totp_cli_try_read_automation_features(
|
||||
TokenInfo* token_info,
|
||||
FuriString* arg,
|
||||
FuriString* args,
|
||||
bool* parsed);
|
||||
|
||||
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag);
|
||||
|
||||
bool totp_cli_try_read_plain_token_secret_encoding(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||
* Modified and optimized for Flipepr Zero device purposes by Alex Kopachov (@akopachov)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
#include "linked_list.h"
|
||||
|
||||
ListNode* list_init_head(void* data) {
|
||||
ListNode* new = malloc(sizeof(ListNode));
|
||||
if(new == NULL) return NULL;
|
||||
new->data = data;
|
||||
new->next = NULL;
|
||||
return new;
|
||||
}
|
||||
|
||||
ListNode* list_add(ListNode* head, void* data) {
|
||||
ListNode* new = malloc(sizeof(ListNode));
|
||||
if(new == NULL) return NULL;
|
||||
new->data = data;
|
||||
new->next = NULL;
|
||||
|
||||
if(head == NULL)
|
||||
head = new;
|
||||
else {
|
||||
ListNode* it;
|
||||
|
||||
for(it = head; it->next != NULL; it = it->next)
|
||||
;
|
||||
|
||||
it->next = new;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
ListNode* list_find(ListNode* head, const void* data) {
|
||||
ListNode* it = NULL;
|
||||
|
||||
for(it = head; it != NULL; it = it->next)
|
||||
if(it->data == data) break;
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
ListNode* list_element_at(ListNode* head, uint16_t index) {
|
||||
ListNode* it;
|
||||
uint16_t i;
|
||||
for(it = head, i = 0; it != NULL && i < index; it = it->next, i++)
|
||||
;
|
||||
return it;
|
||||
}
|
||||
|
||||
ListNode* list_remove(ListNode* head, ListNode* ep) {
|
||||
if(head == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(head == ep) {
|
||||
ListNode* new_head = head->next;
|
||||
free(head);
|
||||
return new_head;
|
||||
}
|
||||
|
||||
ListNode* it;
|
||||
|
||||
for(it = head; it->next != ep; it = it->next)
|
||||
;
|
||||
|
||||
it->next = ep->next;
|
||||
free(ep);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
ListNode* list_remove_at(ListNode* head, uint16_t index, void** removed_node_data) {
|
||||
if(head == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ListNode* it;
|
||||
ListNode* prev = NULL;
|
||||
|
||||
uint16_t i;
|
||||
|
||||
for(it = head, i = 0; it != NULL && i < index; prev = it, it = it->next, i++)
|
||||
;
|
||||
|
||||
if(it == NULL) return head;
|
||||
|
||||
ListNode* new_head = head;
|
||||
if(prev == NULL) {
|
||||
new_head = it->next;
|
||||
} else {
|
||||
prev->next = it->next;
|
||||
}
|
||||
|
||||
if(removed_node_data != NULL) {
|
||||
*removed_node_data = it->data;
|
||||
}
|
||||
|
||||
free(it);
|
||||
|
||||
return new_head;
|
||||
}
|
||||
|
||||
ListNode* list_insert_at(ListNode* head, uint16_t index, void* data) {
|
||||
if(index == 0 || head == NULL) {
|
||||
ListNode* new_head = list_init_head(data);
|
||||
if(new_head != NULL) {
|
||||
new_head->next = head;
|
||||
}
|
||||
return new_head;
|
||||
}
|
||||
|
||||
ListNode* it;
|
||||
ListNode* prev = NULL;
|
||||
|
||||
uint16_t i;
|
||||
|
||||
for(it = head, i = 0; it != NULL && i < index; prev = it, it = it->next, i++)
|
||||
;
|
||||
|
||||
ListNode* new = malloc(sizeof(ListNode));
|
||||
if(new == NULL) return NULL;
|
||||
new->data = data;
|
||||
new->next = it;
|
||||
prev->next = new;
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void list_free(ListNode* head) {
|
||||
ListNode* it = head;
|
||||
ListNode* tmp;
|
||||
|
||||
while(it != NULL) {
|
||||
tmp = it;
|
||||
it = it->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @brief Single linked list node
|
||||
*/
|
||||
typedef struct ListNode {
|
||||
/**
|
||||
* @brief Pointer to the data assigned to the current list node
|
||||
*/
|
||||
void* data;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the next list node
|
||||
*/
|
||||
struct ListNode* next;
|
||||
} ListNode;
|
||||
|
||||
/**
|
||||
* @brief Initializes a new list node head
|
||||
* @param data data to be assigned to the head list node
|
||||
* @return Head list node
|
||||
*/
|
||||
ListNode* list_init_head(void* data);
|
||||
|
||||
/**
|
||||
* @brief Adds new list node to the end of the list
|
||||
* @param head head list node
|
||||
* @param data data to be assigned to the newly added list node
|
||||
* @return Head list node
|
||||
*/
|
||||
ListNode* list_add(
|
||||
ListNode* head,
|
||||
void* data); /* adds element with specified data to the end of the list and returns new head node. */
|
||||
|
||||
/**
|
||||
* @brief Searches list node with the given assigned \p data in the list
|
||||
* @param head head list node
|
||||
* @param data data to be searched
|
||||
* @return List node containing \p data if there is such a node in the list; \c NULL otherwise
|
||||
*/
|
||||
ListNode* list_find(ListNode* head, const void* data);
|
||||
|
||||
/**
|
||||
* @brief Searches list node with the given \p index in the list
|
||||
* @param head head list node
|
||||
* @param index desired list node index
|
||||
* @return List node with the given \p index in the list if there is such a list node; \c NULL otherwise
|
||||
*/
|
||||
ListNode* list_element_at(ListNode* head, uint16_t index);
|
||||
|
||||
/**
|
||||
* @brief Removes list node from the list
|
||||
* @param head head list node
|
||||
* @param ep list node to be removed
|
||||
* @return Head list node
|
||||
*/
|
||||
ListNode* list_remove(ListNode* head, ListNode* ep);
|
||||
|
||||
/**
|
||||
* @brief Removes list node with the given \p index in the list from the list
|
||||
* @param head head list node
|
||||
* @param index index of the node to be removed
|
||||
* @param[out] removed_node_data data which was assigned to the removed list node
|
||||
* @return Head list node
|
||||
*/
|
||||
ListNode* list_remove_at(ListNode* head, uint16_t index, void** removed_node_data);
|
||||
|
||||
/**
|
||||
* @brief Inserts new list node at the given index
|
||||
* @param head head list node
|
||||
* @param index index in the list where the new list node should be inserted
|
||||
* @param data data to be assgned to the new list node
|
||||
* @return Head list node
|
||||
*/
|
||||
ListNode* list_insert_at(ListNode* head, uint16_t index, void* data);
|
||||
|
||||
/**
|
||||
* @brief Disposes all the list nodes in the list
|
||||
* @param head head list node
|
||||
*/
|
||||
void list_free(ListNode* head);
|
||||
|
||||
#define TOTP_LIST_INIT_OR_ADD(head, item, assert) \
|
||||
if(head == NULL) { \
|
||||
head = list_init_head(item); \
|
||||
assert(head != NULL); \
|
||||
} else { \
|
||||
assert(list_add(head, item) != NULL); \
|
||||
}
|
||||
|
||||
#define TOTP_LIST_FOREACH(head, node, action) \
|
||||
ListNode* node = head; \
|
||||
while(node != NULL) { \
|
||||
action node = node->next; \
|
||||
}
|
||||
@@ -25,4 +25,4 @@ TOTP_ROLL_VALUE_FN(int8_t, int8_t)
|
||||
|
||||
TOTP_ROLL_VALUE_FN(uint8_t, int8_t)
|
||||
|
||||
TOTP_ROLL_VALUE_FN(uint16_t, int16_t);
|
||||
TOTP_ROLL_VALUE_FN(size_t, int16_t);
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef uint8_t TotpRollValueOverflowBehavior;
|
||||
|
||||
@@ -47,7 +48,7 @@ TOTP_ROLL_VALUE_FN_HEADER(int8_t, int8_t);
|
||||
TOTP_ROLL_VALUE_FN_HEADER(uint8_t, int8_t);
|
||||
|
||||
/**
|
||||
* @brief Rolls \c uint16_t \p value using \p min and \p max as an value constraints with \p step step.
|
||||
* @brief Rolls \c size_t \p value using \p min and \p max as an value constraints with \p step step.
|
||||
* When value reaches constraint value \p overflow_behavior defines what to do next.
|
||||
* @param[in,out] value value to roll
|
||||
* @param step step to be used to change value
|
||||
@@ -55,4 +56,4 @@ TOTP_ROLL_VALUE_FN_HEADER(uint8_t, int8_t);
|
||||
* @param max maximum possible value
|
||||
* @param overflow_behavior defines what to do when value reaches constraint value
|
||||
*/
|
||||
TOTP_ROLL_VALUE_FN_HEADER(uint16_t, int16_t);
|
||||
TOTP_ROLL_VALUE_FN_HEADER(size_t, int16_t);
|
||||
805
applications/external/totp/services/config/config.c
vendored
805
applications/external/totp/services/config/config.c
vendored
File diff suppressed because it is too large
Load Diff
127
applications/external/totp/services/config/config.h
vendored
127
applications/external/totp/services/config/config.h
vendored
@@ -1,137 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include "../../types/plugin_state.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "config_file_context.h"
|
||||
#include "constants.h"
|
||||
#include "token_info_iterator.h"
|
||||
|
||||
typedef uint8_t TokenLoadingResult;
|
||||
typedef uint8_t TotpConfigFileOpenResult;
|
||||
typedef uint8_t TotpConfigFileUpdateResult;
|
||||
|
||||
/**
|
||||
* @brief Token loading results
|
||||
*/
|
||||
enum TokenLoadingResults {
|
||||
/**
|
||||
* @brief All the tokens loaded successfully
|
||||
*/
|
||||
TokenLoadingResultSuccess,
|
||||
|
||||
/**
|
||||
* @brief All the tokens loaded, but there are some warnings
|
||||
*/
|
||||
TokenLoadingResultWarning,
|
||||
|
||||
/**
|
||||
* @brief Tokens not loaded because of error(s)
|
||||
*/
|
||||
TokenLoadingResultError
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Config file opening result
|
||||
*/
|
||||
enum TotpConfigFileOpenResults {
|
||||
/**
|
||||
* @brief Config file opened successfully
|
||||
*/
|
||||
TotpConfigFileOpenSuccess = 0,
|
||||
|
||||
/**
|
||||
* @brief An error has occurred during opening config file
|
||||
*/
|
||||
TotpConfigFileOpenError = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Config file updating result
|
||||
*/
|
||||
enum TotpConfigFileUpdateResults {
|
||||
/**
|
||||
* @brief Config file updated successfully
|
||||
*/
|
||||
TotpConfigFileUpdateSuccess,
|
||||
|
||||
/**
|
||||
* @brief An error has occurred during updating config file
|
||||
*/
|
||||
TotpConfigFileUpdateError
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tries to take a config file backup
|
||||
* @param plugin_state application state
|
||||
* @return backup path if backup successfully taken; \c NULL otherwise
|
||||
*/
|
||||
char* totp_config_file_backup();
|
||||
|
||||
/**
|
||||
* @brief Saves all the settings and tokens to an application config file
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult totp_full_save_config_file(const PluginState* const plugin_state);
|
||||
char* totp_config_file_backup(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Loads basic information from an application config file into application state without loading all the tokens
|
||||
* @param plugin_state application state
|
||||
* @return Config file open result
|
||||
*/
|
||||
TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Loads tokens from an application config file into application state
|
||||
* @param plugin_state application state
|
||||
* @return Results of the loading
|
||||
*/
|
||||
TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Add new token to the end of the application config file
|
||||
* @param token_info token information to be saved
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult totp_config_file_save_new_token(const TokenInfo* token_info);
|
||||
bool totp_config_file_load(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Updates timezone offset in an application config file
|
||||
* @param new_timezone_offset new timezone offset to be set
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult totp_config_file_update_timezone_offset(float new_timezone_offset);
|
||||
bool totp_config_file_update_timezone_offset(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Updates notification method in an application config file
|
||||
* @param new_notification_method new notification method to be set
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult
|
||||
totp_config_file_update_notification_method(NotificationMethod new_notification_method);
|
||||
bool totp_config_file_update_notification_method(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Updates automation method in an application config file
|
||||
* @param new_automation_method new automation method to be set
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult
|
||||
totp_config_file_update_automation_method(AutomationMethod new_automation_method);
|
||||
bool totp_config_file_update_automation_method(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Updates application user settings
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginState* plugin_state);
|
||||
bool totp_config_file_update_user_settings(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Updates crypto signatures information
|
||||
* @param plugin_state application state
|
||||
* @return Config file update result
|
||||
*/
|
||||
TotpConfigFileUpdateResult
|
||||
totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
|
||||
bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Reset all the settings to default
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_config_file_reset();
|
||||
void totp_config_file_reset(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Closes config file and releases all the resources
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
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
|
||||
* @param plugin_state application state
|
||||
* @param new_pin new user's PIN
|
||||
* @param new_pin_length new user's PIN length
|
||||
* @return \c true if config file encryption successfully updated; \c false otherwise
|
||||
*/
|
||||
bool totp_config_file_update_encryption(
|
||||
PluginState* plugin_state,
|
||||
const uint8_t* new_pin,
|
||||
uint8_t new_pin_length);
|
||||
|
||||
/**
|
||||
* @brief Gets token info iterator context
|
||||
* @param plugin_state application state
|
||||
* @return token info iterator context
|
||||
*/
|
||||
TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state);
|
||||
3
applications/external/totp/services/config/config_file_context.h
vendored
Normal file
3
applications/external/totp/services/config/config_file_context.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct ConfigFileContext ConfigFileContext;
|
||||
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
|
||||
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
|
||||
#define CONFIG_FILE_ACTUAL_VERSION (4)
|
||||
#define CONFIG_FILE_ACTUAL_VERSION (5)
|
||||
|
||||
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
|
||||
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "common_migration.h"
|
||||
#include "../constants.h"
|
||||
#include "../../../types/token_info.h"
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
bool totp_config_migrate_to_latest(
|
||||
FlipperFormat* fff_data_file,
|
||||
@@ -57,18 +58,12 @@ bool totp_config_migrate_to_latest(
|
||||
|
||||
flipper_format_rewind(fff_backup_data_file);
|
||||
|
||||
FuriString* comment_str = furi_string_alloc();
|
||||
|
||||
while(true) {
|
||||
if(!flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_printf(
|
||||
comment_str, "=== BEGIN \"%s\" ===", furi_string_get_cstr(temp_str));
|
||||
flipper_format_write_comment(fff_data_file, comment_str);
|
||||
furi_string_printf(comment_str, "=== END \"%s\" ===", furi_string_get_cstr(temp_str));
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
|
||||
|
||||
flipper_format_read_string(
|
||||
@@ -78,15 +73,32 @@ bool totp_config_migrate_to_latest(
|
||||
if(current_version > 1) {
|
||||
flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
|
||||
|
||||
if(current_version < 5) {
|
||||
uint32_t algo_as_uint32t = SHA1;
|
||||
if(furi_string_cmpi_str(temp_str, TOTP_TOKEN_ALGO_SHA256_NAME) == 0) {
|
||||
algo_as_uint32t = SHA256;
|
||||
} else if(furi_string_cmpi_str(temp_str, TOTP_TOKEN_ALGO_SHA512_NAME) == 0) {
|
||||
algo_as_uint32t = SHA512;
|
||||
} else if(furi_string_cmpi_str(temp_str, TOTP_TOKEN_ALGO_STEAM_NAME) == 0) {
|
||||
algo_as_uint32t = STEAM;
|
||||
}
|
||||
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &algo_as_uint32t, 1);
|
||||
} else {
|
||||
flipper_format_write_string(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
|
||||
}
|
||||
|
||||
flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
|
||||
} else {
|
||||
flipper_format_write_string_cstr(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_TOKEN_ALGO_SHA1_NAME);
|
||||
const uint32_t default_digits = TOTP_6_DIGITS;
|
||||
const uint32_t default_algo = SHA1;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &default_algo, 1);
|
||||
const uint32_t default_digits = TotpSixDigitsCount;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
|
||||
}
|
||||
@@ -108,18 +120,21 @@ bool totp_config_migrate_to_latest(
|
||||
flipper_format_write_string(
|
||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, temp_str);
|
||||
} else {
|
||||
const uint32_t default_automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
|
||||
const uint32_t default_automation_features = TokenAutomationFeatureNone;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file,
|
||||
TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES,
|
||||
&default_automation_features,
|
||||
1);
|
||||
}
|
||||
|
||||
flipper_format_write_comment(fff_data_file, comment_str);
|
||||
}
|
||||
|
||||
furi_string_free(comment_str);
|
||||
Stream* stream = flipper_format_get_raw_stream(fff_data_file);
|
||||
size_t current_pos = stream_tell(stream);
|
||||
size_t total_size = stream_size(stream);
|
||||
if(current_pos < total_size) {
|
||||
stream_delete(stream, total_size - current_pos);
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
/**
|
||||
* @brief Migrates config file to the latest version
|
||||
* @param fff_data_file original config file to be migrated
|
||||
* @param fff_backup_data_file backup copy of original config file
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
bool totp_config_migrate_to_latest(
|
||||
FlipperFormat* fff_data_file,
|
||||
FlipperFormat* fff_backup_data_file);
|
||||
FlipperFormat* fff_backup_data_file);
|
||||
|
||||
551
applications/external/totp/services/config/token_info_iterator.c
vendored
Normal file
551
applications/external/totp/services/config/token_info_iterator.c
vendored
Normal file
@@ -0,0 +1,551 @@
|
||||
#include "token_info_iterator.h"
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <flipper_format/flipper_format_stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include "../../types/common.h"
|
||||
|
||||
#define CONFIG_FILE_PART_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf.part"
|
||||
#define STREAM_COPY_BUFFER_SIZE 128
|
||||
|
||||
struct TokenInfoIteratorContext {
|
||||
size_t total_count;
|
||||
size_t current_index;
|
||||
size_t last_seek_offset;
|
||||
size_t last_seek_index;
|
||||
TokenInfo* current_token;
|
||||
FlipperFormat* config_file;
|
||||
uint8_t* iv;
|
||||
Storage* storage;
|
||||
};
|
||||
|
||||
static bool
|
||||
flipper_format_seek_to_siblinig_token_start(Stream* stream, StreamDirection direction) {
|
||||
char buffer[sizeof(TOTP_CONFIG_KEY_TOKEN_NAME) + 1];
|
||||
bool found = false;
|
||||
while(!found) {
|
||||
if(!stream_seek_to_char(stream, '\n', direction)) {
|
||||
break;
|
||||
}
|
||||
|
||||
size_t buffer_read_size;
|
||||
if((buffer_read_size = stream_read(stream, (uint8_t*)&buffer[0], sizeof(buffer))) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_seek(stream, -(int32_t)buffer_read_size, StreamOffsetFromCurrent)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(strncmp(buffer, "\n" TOTP_CONFIG_KEY_TOKEN_NAME ":", sizeof(buffer)) == 0) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool seek_to_token(size_t token_index, TokenInfoIteratorContext* context) {
|
||||
furi_check(context != NULL && context->config_file != NULL);
|
||||
if(token_index >= context->total_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream* stream = flipper_format_get_raw_stream(context->config_file);
|
||||
long token_index_diff = (long)token_index - (long)context->last_seek_index;
|
||||
size_t token_index_diff_weight = (size_t)labs(token_index_diff);
|
||||
StreamDirection direction = token_index_diff >= 0 ? StreamDirectionForward :
|
||||
StreamDirectionBackward;
|
||||
if(token_index_diff_weight > token_index || context->last_seek_offset == 0) {
|
||||
context->last_seek_offset = 0;
|
||||
context->last_seek_index = 0;
|
||||
token_index_diff = token_index + 1;
|
||||
direction = StreamDirectionForward;
|
||||
} else if(token_index_diff_weight > (context->total_count - token_index - 1)) {
|
||||
context->last_seek_offset = stream_size(stream);
|
||||
context->last_seek_index = context->total_count - 1;
|
||||
token_index_diff = -(long)(context->total_count - token_index);
|
||||
direction = StreamDirectionBackward;
|
||||
}
|
||||
|
||||
stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart);
|
||||
|
||||
if(token_index_diff != 0) {
|
||||
long i = 0;
|
||||
long i_inc = token_index_diff >= 0 ? 1 : -1;
|
||||
do {
|
||||
if(!flipper_format_seek_to_siblinig_token_start(stream, direction)) {
|
||||
break;
|
||||
}
|
||||
|
||||
i += i_inc;
|
||||
} while((i_inc > 0 && i < token_index_diff) || (i_inc < 0 && i > token_index_diff));
|
||||
|
||||
if((i_inc > 0 && i < token_index_diff) || (i_inc < 0 && i > token_index_diff)) {
|
||||
context->last_seek_offset = 0;
|
||||
FURI_LOG_D(LOGGING_TAG, "Was not able to move");
|
||||
return false;
|
||||
}
|
||||
|
||||
context->last_seek_offset = stream_tell(stream);
|
||||
context->last_seek_index = token_index;
|
||||
} else {
|
||||
if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool stream_insert_stream(Stream* dst, Stream* src) {
|
||||
uint8_t buffer[STREAM_COPY_BUFFER_SIZE];
|
||||
size_t buffer_read_size;
|
||||
while((buffer_read_size = stream_read(src, buffer, sizeof(buffer))) != 0) {
|
||||
if(!stream_insert(dst, buffer, buffer_read_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ensure_stream_ends_with_lf(Stream* stream) {
|
||||
uint8_t last_char;
|
||||
size_t original_pos = stream_tell(stream);
|
||||
if(!stream_seek(stream, -1, StreamOffsetFromEnd) || stream_read(stream, &last_char, 1) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t lf = '\n';
|
||||
if(last_char != lf && !stream_write(stream, &lf, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!stream_seek(stream, original_pos, StreamOffsetFromStart)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
totp_token_info_iterator_save_current_token_info_changes(TokenInfoIteratorContext* context) {
|
||||
bool is_new_token = context->current_index >= context->total_count;
|
||||
Stream* stream = flipper_format_get_raw_stream(context->config_file);
|
||||
if(is_new_token) {
|
||||
if(!ensure_stream_ends_with_lf(stream) ||
|
||||
!flipper_format_seek_to_end(context->config_file)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(!seek_to_token(context->current_index, context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset_start = stream_tell(stream);
|
||||
|
||||
size_t offset_end;
|
||||
if(is_new_token) {
|
||||
offset_end = offset_start;
|
||||
} else if(context->current_index + 1 >= context->total_count) {
|
||||
offset_end = stream_size(stream);
|
||||
} else if(seek_to_token(context->current_index + 1, context)) {
|
||||
offset_end = stream_tell(stream);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
FlipperFormat* temp_ff = flipper_format_file_alloc(context->storage);
|
||||
if(!flipper_format_file_open_always(temp_ff, CONFIG_FILE_PART_FILE_PATH)) {
|
||||
flipper_format_free(temp_ff);
|
||||
return false;
|
||||
}
|
||||
|
||||
TokenInfo* token_info = context->current_token;
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_write_string(temp_ff, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_hex(
|
||||
temp_ff,
|
||||
TOTP_CONFIG_KEY_TOKEN_SECRET,
|
||||
token_info->token,
|
||||
token_info->token_length)) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t tmp_uint32 = token_info->algo;
|
||||
if(!flipper_format_write_uint32(temp_ff, TOTP_CONFIG_KEY_TOKEN_ALGO, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = token_info->digits;
|
||||
if(!flipper_format_write_uint32(temp_ff, TOTP_CONFIG_KEY_TOKEN_DIGITS, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = token_info->duration;
|
||||
if(!flipper_format_write_uint32(temp_ff, TOTP_CONFIG_KEY_TOKEN_DURATION, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = token_info->automation_features;
|
||||
if(!flipper_format_write_uint32(
|
||||
temp_ff, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Stream* temp_stream = flipper_format_get_raw_stream(temp_ff);
|
||||
|
||||
if(!stream_rewind(temp_stream)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_seek(stream, offset_start, StreamOffsetFromStart)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(offset_end != offset_start && !stream_delete(stream, offset_end - offset_start)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!is_new_token && !stream_write_char(stream, '\n')) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_insert_stream(stream, temp_stream)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(is_new_token) {
|
||||
context->total_count++;
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(temp_ff);
|
||||
storage_common_remove(context->storage, CONFIG_FILE_PART_FILE_PATH);
|
||||
|
||||
stream_seek(stream, offset_start, StreamOffsetFromStart);
|
||||
context->last_seek_offset = offset_start;
|
||||
context->last_seek_index = context->current_index;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext*
|
||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv) {
|
||||
Stream* stream = flipper_format_get_raw_stream(config_file);
|
||||
stream_rewind(stream);
|
||||
size_t tokens_count = 0;
|
||||
while(true) {
|
||||
if(!flipper_format_seek_to_siblinig_token_start(stream, StreamDirectionForward)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tokens_count++;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext* context = malloc(sizeof(TokenInfoIteratorContext));
|
||||
furi_check(context != NULL);
|
||||
|
||||
context->total_count = tokens_count;
|
||||
context->current_token = token_info_alloc();
|
||||
context->config_file = config_file;
|
||||
context->iv = iv;
|
||||
context->storage = storage;
|
||||
return context;
|
||||
}
|
||||
|
||||
void totp_token_info_iterator_free(TokenInfoIteratorContext* context) {
|
||||
if(context == NULL) return;
|
||||
token_info_free(context->current_token);
|
||||
free(context);
|
||||
}
|
||||
|
||||
bool totp_token_info_iterator_remove_current_token_info(TokenInfoIteratorContext* context) {
|
||||
if(!seek_to_token(context->current_index, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream* stream = flipper_format_get_raw_stream(context->config_file);
|
||||
size_t begin_offset = stream_tell(stream);
|
||||
size_t end_offset;
|
||||
if(!ensure_stream_ends_with_lf(stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(context->current_index >= context->total_count - 1) {
|
||||
end_offset = stream_size(stream) - 1;
|
||||
} else if(seek_to_token(context->current_index + 1, context)) {
|
||||
end_offset = stream_tell(stream);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!stream_seek(stream, begin_offset, StreamOffsetFromStart) ||
|
||||
!stream_delete(stream, end_offset - begin_offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
context->total_count--;
|
||||
if(context->current_index >= context->total_count) {
|
||||
context->current_index = context->total_count - 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool totp_token_info_iterator_move_current_token_info(
|
||||
TokenInfoIteratorContext* context,
|
||||
size_t new_index) {
|
||||
if(context->current_index == new_index) return true;
|
||||
|
||||
Stream* stream = flipper_format_get_raw_stream(context->config_file);
|
||||
|
||||
if(!ensure_stream_ends_with_lf(stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!seek_to_token(context->current_index, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t begin_offset = stream_tell(stream);
|
||||
size_t end_offset;
|
||||
if(context->current_index >= context->total_count - 1) {
|
||||
end_offset = stream_size(stream) - 1;
|
||||
} else if(seek_to_token(context->current_index + 1, context)) {
|
||||
end_offset = stream_tell(stream);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream* temp_stream = file_stream_alloc(context->storage);
|
||||
if(!file_stream_open(
|
||||
temp_stream, CONFIG_FILE_PART_FILE_PATH, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
stream_free(temp_stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t moving_size = end_offset - begin_offset;
|
||||
|
||||
bool result = false;
|
||||
do {
|
||||
if(!stream_seek(stream, begin_offset, StreamOffsetFromStart)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(stream_copy(stream, temp_stream, moving_size) < moving_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_rewind(temp_stream)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_seek(stream, begin_offset, StreamOffsetFromStart)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!stream_delete(stream, moving_size)) {
|
||||
break;
|
||||
}
|
||||
|
||||
context->last_seek_offset = 0;
|
||||
context->last_seek_index = 0;
|
||||
if(new_index >= context->total_count - 1) {
|
||||
if(!stream_seek(stream, stream_size(stream) - 1, StreamOffsetFromStart)) {
|
||||
break;
|
||||
}
|
||||
} else if(!seek_to_token(new_index, context)) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = stream_insert_stream(stream, temp_stream);
|
||||
} while(false);
|
||||
|
||||
stream_free(temp_stream);
|
||||
storage_common_remove(context->storage, CONFIG_FILE_PART_FILE_PATH);
|
||||
|
||||
context->last_seek_offset = 0;
|
||||
context->last_seek_index = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TotpIteratorUpdateTokenResult totp_token_info_iterator_update_current_token(
|
||||
TokenInfoIteratorContext* context,
|
||||
TOTP_ITERATOR_UPDATE_TOKEN_ACTION update,
|
||||
const void* update_context) {
|
||||
TotpIteratorUpdateTokenResult result = update(context->current_token, update_context);
|
||||
if(result == TotpIteratorUpdateTokenResultSuccess) {
|
||||
if(!totp_token_info_iterator_save_current_token_info_changes(context)) {
|
||||
result = TotpIteratorUpdateTokenResultFileUpdateFailed;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
totp_token_info_iterator_go_to(context, context->current_index);
|
||||
return result;
|
||||
}
|
||||
|
||||
TotpIteratorUpdateTokenResult totp_token_info_iterator_add_new_token(
|
||||
TokenInfoIteratorContext* context,
|
||||
TOTP_ITERATOR_UPDATE_TOKEN_ACTION update,
|
||||
const void* update_context) {
|
||||
size_t previous_index = context->current_index;
|
||||
context->current_index = context->total_count;
|
||||
token_info_set_defaults(context->current_token);
|
||||
TotpIteratorUpdateTokenResult result = update(context->current_token, update_context);
|
||||
if(result == TotpIteratorUpdateTokenResultSuccess &&
|
||||
!totp_token_info_iterator_save_current_token_info_changes(context)) {
|
||||
result = TotpIteratorUpdateTokenResultFileUpdateFailed;
|
||||
}
|
||||
|
||||
if(result != TotpIteratorUpdateTokenResultSuccess) {
|
||||
totp_token_info_iterator_go_to(context, previous_index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t token_index) {
|
||||
furi_check(context != NULL);
|
||||
context->current_index = token_index;
|
||||
if(!seek_to_token(context->current_index, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream* stream = flipper_format_get_raw_stream(context->config_file);
|
||||
size_t original_offset = stream_tell(stream);
|
||||
|
||||
if(!flipper_format_read_string(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_NAME, context->current_token->name)) {
|
||||
stream_seek(stream, original_offset, StreamOffsetFromStart);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t secret_bytes_count;
|
||||
if(!flipper_format_get_value_count(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_SECRET, &secret_bytes_count)) {
|
||||
secret_bytes_count = 0;
|
||||
}
|
||||
TokenInfo* tokenInfo = context->current_token;
|
||||
bool token_update_needed = false;
|
||||
if(tokenInfo->token != NULL) {
|
||||
free(tokenInfo->token);
|
||||
tokenInfo->token_length = 0;
|
||||
}
|
||||
|
||||
if(secret_bytes_count == 1) { // Plain secret key
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
if(flipper_format_read_string(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str)) {
|
||||
if(token_info_set_secret(
|
||||
tokenInfo,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
PlainTokenSecretEncodingBase32,
|
||||
context->iv)) {
|
||||
FURI_LOG_W(
|
||||
LOGGING_TAG,
|
||||
"Token \"%s\" has plain secret",
|
||||
furi_string_get_cstr(tokenInfo->name));
|
||||
token_update_needed = true;
|
||||
} else {
|
||||
tokenInfo->token = NULL;
|
||||
tokenInfo->token_length = 0;
|
||||
FURI_LOG_W(
|
||||
LOGGING_TAG,
|
||||
"Token \"%s\" has invalid secret",
|
||||
furi_string_get_cstr(tokenInfo->name));
|
||||
}
|
||||
} else {
|
||||
tokenInfo->token = NULL;
|
||||
tokenInfo->token_length = 0;
|
||||
}
|
||||
|
||||
furi_string_free(temp_str);
|
||||
} else { // encrypted
|
||||
tokenInfo->token_length = secret_bytes_count;
|
||||
if(secret_bytes_count > 0) {
|
||||
tokenInfo->token = malloc(tokenInfo->token_length);
|
||||
furi_check(tokenInfo->token != NULL);
|
||||
if(!flipper_format_read_hex(
|
||||
context->config_file,
|
||||
TOTP_CONFIG_KEY_TOKEN_SECRET,
|
||||
tokenInfo->token,
|
||||
tokenInfo->token_length)) {
|
||||
free(tokenInfo->token);
|
||||
tokenInfo->token = NULL;
|
||||
tokenInfo->token_length = 0;
|
||||
}
|
||||
} else {
|
||||
tokenInfo->token = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t temp_data32;
|
||||
if(flipper_format_read_uint32(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &temp_data32, 1) &&
|
||||
temp_data32 <= STEAM) {
|
||||
tokenInfo->algo = (TokenHashAlgo)temp_data32;
|
||||
} else {
|
||||
tokenInfo->algo = SHA1;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1) ||
|
||||
!token_info_set_digits_from_int(tokenInfo, temp_data32)) {
|
||||
tokenInfo->digits = TotpSixDigitsCount;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_DURATION, &temp_data32, 1) ||
|
||||
!token_info_set_duration_from_int(tokenInfo, temp_data32)) {
|
||||
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
|
||||
}
|
||||
|
||||
if(flipper_format_read_uint32(
|
||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, &temp_data32, 1)) {
|
||||
tokenInfo->automation_features = temp_data32;
|
||||
} else {
|
||||
tokenInfo->automation_features = TokenAutomationFeatureNone;
|
||||
}
|
||||
|
||||
stream_seek(stream, original_offset, StreamOffsetFromStart);
|
||||
|
||||
if(token_update_needed && !totp_token_info_iterator_save_current_token_info_changes(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const TokenInfo*
|
||||
totp_token_info_iterator_get_current_token(const TokenInfoIteratorContext* context) {
|
||||
return context->current_token;
|
||||
}
|
||||
|
||||
size_t totp_token_info_iterator_get_current_token_index(const TokenInfoIteratorContext* context) {
|
||||
return context->current_index;
|
||||
}
|
||||
|
||||
size_t totp_token_info_iterator_get_total_count(const TokenInfoIteratorContext* context) {
|
||||
return context->total_count;
|
||||
}
|
||||
|
||||
void totp_token_info_iterator_attach_to_config_file(
|
||||
TokenInfoIteratorContext* context,
|
||||
FlipperFormat* config_file) {
|
||||
context->config_file = config_file;
|
||||
}
|
||||
121
applications/external/totp/services/config/token_info_iterator.h
vendored
Normal file
121
applications/external/totp/services/config/token_info_iterator.h
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../types/token_info.h"
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include "constants.h"
|
||||
|
||||
typedef int TotpIteratorUpdateTokenResult;
|
||||
|
||||
typedef TotpIteratorUpdateTokenResult (
|
||||
*TOTP_ITERATOR_UPDATE_TOKEN_ACTION)(TokenInfo* const token_info, const void* context);
|
||||
|
||||
typedef struct TokenInfoIteratorContext TokenInfoIteratorContext;
|
||||
|
||||
enum TotpIteratorUpdateTokenResults {
|
||||
|
||||
/**
|
||||
* @brief Token successfully updated
|
||||
*/
|
||||
TotpIteratorUpdateTokenResultSuccess = 0,
|
||||
|
||||
/**
|
||||
* @brief An error ocurred during updating config file
|
||||
*/
|
||||
TotpIteratorUpdateTokenResultFileUpdateFailed = -1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initializes a new token info iterator
|
||||
* @param storage storage reference
|
||||
* @param config_file config file to use
|
||||
* @param iv initialization vector (IV) to be used for encryption\decryption
|
||||
* @return Token info iterator context
|
||||
*/
|
||||
TokenInfoIteratorContext*
|
||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv);
|
||||
|
||||
/**
|
||||
* @brief Navigates iterator to the token with given index
|
||||
* @param context token info iterator context
|
||||
* @param token_index token index to navigate to
|
||||
* @return \c true if navigation succeeded; \c false otherwise
|
||||
*/
|
||||
bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t token_index);
|
||||
|
||||
/**
|
||||
* @brief Moves current token to a given new index
|
||||
* @param context token info iterator context
|
||||
* @param new_index new token index to move current token to
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
bool totp_token_info_iterator_move_current_token_info(
|
||||
TokenInfoIteratorContext* context,
|
||||
size_t new_index);
|
||||
|
||||
/**
|
||||
* @brief Updates current token info using given update action
|
||||
* @param context token info iterator context
|
||||
* @param update action which is responsible to make all the necessary updates to token info
|
||||
* @param update_context update action context
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
TotpIteratorUpdateTokenResult totp_token_info_iterator_update_current_token(
|
||||
TokenInfoIteratorContext* context,
|
||||
TOTP_ITERATOR_UPDATE_TOKEN_ACTION update,
|
||||
const void* update_context);
|
||||
|
||||
/**
|
||||
* @brief Adds new token info to the end of the list using given update action
|
||||
* @param context token info iterator context
|
||||
* @param update action which is responsible to make all the necessary updates to token info
|
||||
* @param update_context update action context
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
TotpIteratorUpdateTokenResult totp_token_info_iterator_add_new_token(
|
||||
TokenInfoIteratorContext* context,
|
||||
TOTP_ITERATOR_UPDATE_TOKEN_ACTION update,
|
||||
const void* update_context);
|
||||
|
||||
/**
|
||||
* @brief Remvoves current token info
|
||||
* @param context token info iterator context
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
bool totp_token_info_iterator_remove_current_token_info(TokenInfoIteratorContext* context);
|
||||
|
||||
/**
|
||||
* @brief Disposes token info iterator and releases all the resources
|
||||
* @param context token info iterator context
|
||||
*/
|
||||
void totp_token_info_iterator_free(TokenInfoIteratorContext* context);
|
||||
|
||||
/**
|
||||
* @brief Gets current token info
|
||||
* @param context token info iterator context
|
||||
* @return current token info
|
||||
*/
|
||||
const TokenInfo*
|
||||
totp_token_info_iterator_get_current_token(const TokenInfoIteratorContext* context);
|
||||
|
||||
/**
|
||||
* @brief Gets current token info index
|
||||
* @param context token info iterator context
|
||||
* @return current token info index
|
||||
*/
|
||||
size_t totp_token_info_iterator_get_current_token_index(const TokenInfoIteratorContext* context);
|
||||
|
||||
/**
|
||||
* @brief Gets total amount of token infos found
|
||||
* @param context token info iterator context
|
||||
* @return amount of token infos found
|
||||
*/
|
||||
size_t totp_token_info_iterator_get_total_count(const TokenInfoIteratorContext* context);
|
||||
|
||||
/**
|
||||
* @brief Attaches token info iterator to another config file
|
||||
* @param context token info iterator context
|
||||
* @param config_file config file reference to attach token info iterator to
|
||||
*/
|
||||
void totp_token_info_iterator_attach_to_config_file(
|
||||
TokenInfoIteratorContext* context,
|
||||
FlipperFormat* config_file);
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <furi_hal_crypto.h>
|
||||
#include <furi_hal_random.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include "../config/config.h"
|
||||
#include "../../types/common.h"
|
||||
#include "memset_s.h"
|
||||
|
||||
@@ -62,9 +61,11 @@ uint8_t* totp_crypto_decrypt(
|
||||
return decrypted_data;
|
||||
}
|
||||
|
||||
bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
|
||||
CryptoSeedIVResult result;
|
||||
if(plugin_state->crypto_verify_data == NULL) {
|
||||
FURI_LOG_D(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);
|
||||
}
|
||||
|
||||
@@ -95,9 +96,9 @@ bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
result = CryptoSeedIVResultFlagSuccess;
|
||||
if(plugin_state->crypto_verify_data == NULL) {
|
||||
FURI_LOG_D(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);
|
||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
||||
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
||||
@@ -110,8 +111,7 @@ bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t
|
||||
|
||||
plugin_state->pin_set = pin != NULL && pin_length > 0;
|
||||
|
||||
result = totp_config_file_update_crypto_signatures(plugin_state) ==
|
||||
TotpConfigFileUpdateSuccess;
|
||||
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -2,6 +2,26 @@
|
||||
|
||||
#include "../../types/plugin_state.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
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||
* @param plain_data plain data to be encrypted
|
||||
@@ -35,9 +55,10 @@ uint8_t* totp_crypto_decrypt(
|
||||
* @param plugin_state application state
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
* @return \c true on success; \c false otherwise
|
||||
* @return Results of seeding IV
|
||||
*/
|
||||
bool totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length);
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv(PluginState* plugin_state, 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
|
||||
|
||||
43
applications/external/totp/totp_app.c
vendored
43
applications/external/totp/totp_app.c
vendored
@@ -51,23 +51,39 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
||||
dialog_message_show(plugin_state->dialogs_app, message);
|
||||
dialog_message_free(message);
|
||||
if(dialog_result == DialogMessageButtonRight) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||
} else {
|
||||
if(!totp_crypto_seed_iv(plugin_state, NULL, 0)) {
|
||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0);
|
||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
} else if(seed_result == CryptoSeedIVResultFailed) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
}
|
||||
} else if(plugin_state->pin_set) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||
} else {
|
||||
if(!totp_crypto_seed_iv(plugin_state, NULL, 0)) {
|
||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0);
|
||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
} else if(seed_result == CryptoSeedIVResultFailed) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(totp_crypto_verify_key(plugin_state)) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
LOGGING_TAG,
|
||||
@@ -96,7 +112,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
||||
|
||||
if(totp_config_file_load_base(plugin_state) != TotpConfigFileOpenSuccess) {
|
||||
if(!totp_config_file_load(plugin_state)) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
@@ -119,15 +135,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
ListNode* node = plugin_state->tokens_list;
|
||||
ListNode* tmp;
|
||||
while(node != NULL) {
|
||||
tmp = node->next;
|
||||
TokenInfo* tokenInfo = node->data;
|
||||
token_info_free(tokenInfo);
|
||||
free(node);
|
||||
node = tmp;
|
||||
}
|
||||
totp_config_file_close(plugin_state);
|
||||
|
||||
if(plugin_state->crypto_verify_data != NULL) {
|
||||
free(plugin_state->crypto_verify_data);
|
||||
@@ -193,8 +201,9 @@ int32_t totp_app() {
|
||||
}
|
||||
} else if(
|
||||
plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication &&
|
||||
plugin_state->current_scene != TotpSceneStandby &&
|
||||
furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
|
||||
3
applications/external/totp/types/common.c
vendored
Normal file
3
applications/external/totp/types/common.c
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "common.h"
|
||||
|
||||
const char* LOGGING_TAG = "TOTP APP";
|
||||
2
applications/external/totp/types/common.h
vendored
2
applications/external/totp/types/common.h
vendored
@@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define LOGGING_TAG "TOTP APP"
|
||||
extern const char* LOGGING_TAG;
|
||||
|
||||
17
applications/external/totp/types/nullable.h
vendored
17
applications/external/totp/types/nullable.h
vendored
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define TOTP_NULLABLE_STRUCT(value_type) \
|
||||
typedef struct TotpNullable_##value_type { \
|
||||
bool is_null; \
|
||||
value_type value; \
|
||||
} TotpNullable_##value_type
|
||||
|
||||
#define TOTP_NULLABLE_NULL(s) s.is_null = true
|
||||
#define TOTP_NULLABLE_VALUE(s, v) \
|
||||
s.is_null = false; \
|
||||
s.value = v
|
||||
|
||||
TOTP_NULLABLE_STRUCT(uint16_t);
|
||||
17
applications/external/totp/types/plugin_state.h
vendored
17
applications/external/totp/types/plugin_state.h
vendored
@@ -4,8 +4,8 @@
|
||||
#include <gui/gui.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include "../features_config.h"
|
||||
#include <linked_list.h>
|
||||
#include "../ui/totp_scenes_enum.h"
|
||||
#include "../services/config/config_file_context.h"
|
||||
#include "notification_method.h"
|
||||
#include "automation_method.h"
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
@@ -48,20 +48,7 @@ typedef struct {
|
||||
*/
|
||||
float timezone_offset;
|
||||
|
||||
/**
|
||||
* @brief Token list head node
|
||||
*/
|
||||
ListNode* tokens_list;
|
||||
|
||||
/**
|
||||
* @brief Whether token list is loaded or not
|
||||
*/
|
||||
bool token_list_loaded;
|
||||
|
||||
/**
|
||||
* @brief Tokens list length
|
||||
*/
|
||||
uint16_t tokens_count;
|
||||
ConfigFileContext* config_file_context;
|
||||
|
||||
/**
|
||||
* @brief Encrypted well-known string data
|
||||
|
||||
45
applications/external/totp/types/token_info.c
vendored
45
applications/external/totp/types/token_info.c
vendored
@@ -8,17 +8,15 @@
|
||||
TokenInfo* token_info_alloc() {
|
||||
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
|
||||
furi_check(tokenInfo != NULL);
|
||||
tokenInfo->algo = SHA1;
|
||||
tokenInfo->digits = TOTP_6_DIGITS;
|
||||
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
|
||||
tokenInfo->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
|
||||
tokenInfo->name = furi_string_alloc();
|
||||
token_info_set_defaults(tokenInfo);
|
||||
return tokenInfo;
|
||||
}
|
||||
|
||||
void token_info_free(TokenInfo* token_info) {
|
||||
if(token_info == NULL) return;
|
||||
free(token_info->name);
|
||||
free(token_info->token);
|
||||
furi_string_free(token_info->name);
|
||||
free(token_info);
|
||||
}
|
||||
|
||||
@@ -32,13 +30,13 @@ bool token_info_set_secret(
|
||||
uint8_t* plain_secret;
|
||||
size_t plain_secret_length;
|
||||
size_t plain_secret_size;
|
||||
if(plain_token_secret_encoding == PLAIN_TOKEN_ENCODING_BASE32) {
|
||||
if(plain_token_secret_encoding == PlainTokenSecretEncodingBase32) {
|
||||
plain_secret_size = token_secret_length;
|
||||
plain_secret = malloc(plain_secret_size);
|
||||
furi_check(plain_secret != NULL);
|
||||
plain_secret_length =
|
||||
base32_decode((const uint8_t*)plain_token_secret, plain_secret, plain_secret_size);
|
||||
} else if(plain_token_secret_encoding == PLAIN_TOKEN_ENCODING_BASE64) {
|
||||
} else if(plain_token_secret_encoding == PlainTokenSecretEncodingBase64) {
|
||||
plain_secret_length = 0;
|
||||
plain_secret = base64_decode(
|
||||
(const uint8_t*)plain_token_secret,
|
||||
@@ -52,6 +50,10 @@ bool token_info_set_secret(
|
||||
|
||||
bool result;
|
||||
if(plain_secret_length > 0) {
|
||||
if(token_info->token != NULL) {
|
||||
free(token_info->token);
|
||||
}
|
||||
|
||||
token_info->token =
|
||||
totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
|
||||
result = true;
|
||||
@@ -67,13 +69,13 @@ bool token_info_set_secret(
|
||||
bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
|
||||
switch(digits) {
|
||||
case 5:
|
||||
token_info->digits = TOTP_5_DIGITS;
|
||||
token_info->digits = TotpFiveDigitsCount;
|
||||
return true;
|
||||
case 6:
|
||||
token_info->digits = TOTP_6_DIGITS;
|
||||
token_info->digits = TotpSixDigitsCount;
|
||||
return true;
|
||||
case 8:
|
||||
token_info->digits = TOTP_8_DIGITS;
|
||||
token_info->digits = TotpEightDigitsCount;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
@@ -134,22 +136,22 @@ char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
|
||||
|
||||
bool token_info_set_automation_feature_from_str(TokenInfo* token_info, const FuriString* str) {
|
||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END_NAME) == 0) {
|
||||
token_info->automation_features |= TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END;
|
||||
token_info->automation_features |= TokenAutomationFeatureEnterAtTheEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME) == 0) {
|
||||
token_info->automation_features |= TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END;
|
||||
token_info->automation_features |= TokenAutomationFeatureTabAtTheEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME) == 0) {
|
||||
token_info->automation_features |= TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER;
|
||||
token_info->automation_features |= TokenAutomationFeatureTypeSlower;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME) == 0) {
|
||||
token_info->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
|
||||
token_info->automation_features = TokenAutomationFeatureNone;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -164,10 +166,17 @@ TokenInfo* token_info_clone(const TokenInfo* src) {
|
||||
furi_check(clone->token != NULL);
|
||||
memcpy(clone->token, src->token, src->token_length);
|
||||
|
||||
int name_length = strnlen(src->name, TOTP_TOKEN_MAX_LENGTH);
|
||||
clone->name = malloc(name_length + 1);
|
||||
furi_check(clone->name != NULL);
|
||||
strlcpy(clone->name, src->name, name_length + 1);
|
||||
clone->name = furi_string_alloc();
|
||||
furi_string_set(clone->name, src->name);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
void token_info_set_defaults(TokenInfo* token_info) {
|
||||
furi_check(token_info != NULL);
|
||||
token_info->algo = SHA1;
|
||||
token_info->digits = TotpSixDigitsCount;
|
||||
token_info->duration = TOTP_TOKEN_DURATION_DEFAULT;
|
||||
token_info->automation_features = TokenAutomationFeatureNone;
|
||||
furi_string_reset(token_info->name);
|
||||
}
|
||||
42
applications/external/totp/types/token_info.h
vendored
42
applications/external/totp/types/token_info.h
vendored
@@ -20,6 +20,8 @@
|
||||
#define TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME "tab"
|
||||
#define TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME "slower"
|
||||
|
||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT (8)
|
||||
|
||||
typedef uint8_t TokenHashAlgo;
|
||||
typedef uint8_t TokenDigitsCount;
|
||||
typedef uint8_t TokenAutomationFeature;
|
||||
@@ -32,22 +34,22 @@ enum TokenHashAlgos {
|
||||
/**
|
||||
* @brief SHA1 hashing algorithm
|
||||
*/
|
||||
SHA1,
|
||||
SHA1 = 0,
|
||||
|
||||
/**
|
||||
* @brief SHA256 hashing algorithm
|
||||
*/
|
||||
SHA256,
|
||||
SHA256 = 1,
|
||||
|
||||
/**
|
||||
* @brief SHA512 hashing algorithm
|
||||
*/
|
||||
SHA512,
|
||||
SHA512 = 2,
|
||||
|
||||
/**
|
||||
* @brief Algorithm used by Steam (Valve)
|
||||
*/
|
||||
STEAM
|
||||
STEAM = 3
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -55,19 +57,19 @@ enum TokenHashAlgos {
|
||||
*/
|
||||
enum TokenDigitsCounts {
|
||||
/**
|
||||
* @brief 6 digits
|
||||
* @brief 5 digits
|
||||
*/
|
||||
TOTP_5_DIGITS = 5,
|
||||
TotpFiveDigitsCount = 5,
|
||||
|
||||
/**
|
||||
* @brief 6 digits
|
||||
*/
|
||||
TOTP_6_DIGITS = 6,
|
||||
TotpSixDigitsCount = 6,
|
||||
|
||||
/**
|
||||
* @brief 8 digits
|
||||
*/
|
||||
TOTP_8_DIGITS = 8
|
||||
TotpEightDigitsCount = 8
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -77,22 +79,22 @@ enum TokenAutomationFeatures {
|
||||
/**
|
||||
* @brief No features enabled
|
||||
*/
|
||||
TOKEN_AUTOMATION_FEATURE_NONE = 0b000,
|
||||
TokenAutomationFeatureNone = 0b000,
|
||||
|
||||
/**
|
||||
* @brief Press "Enter" key at the end as a part of token input automation
|
||||
*/
|
||||
TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END = 0b001,
|
||||
TokenAutomationFeatureEnterAtTheEnd = 0b001,
|
||||
|
||||
/**
|
||||
* @brief Press "Tab" key at the end as a part of token input automation
|
||||
*/
|
||||
TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END = 0b010,
|
||||
TokenAutomationFeatureTabAtTheEnd = 0b010,
|
||||
|
||||
/**
|
||||
* @brief Press keys slower and wait longer between keystrokes
|
||||
*/
|
||||
TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER = 0b100
|
||||
TokenAutomationFeatureTypeSlower = 0b100
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -103,16 +105,14 @@ enum PlainTokenSecretEncodings {
|
||||
/**
|
||||
* @brief Base32 encoding
|
||||
*/
|
||||
PLAIN_TOKEN_ENCODING_BASE32 = 0,
|
||||
PlainTokenSecretEncodingBase32 = 0,
|
||||
|
||||
/**
|
||||
* @brief Base64 encoding
|
||||
*/
|
||||
PLAIN_TOKEN_ENCODING_BASE64 = 1
|
||||
PlainTokenSecretEncodingBase64 = 1
|
||||
};
|
||||
|
||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT (8)
|
||||
|
||||
/**
|
||||
* @brief TOTP token information
|
||||
*/
|
||||
@@ -130,7 +130,7 @@ typedef struct {
|
||||
/**
|
||||
* @brief User-friendly token name
|
||||
*/
|
||||
char* name;
|
||||
FuriString* name;
|
||||
|
||||
/**
|
||||
* @brief Hashing algorithm
|
||||
@@ -225,4 +225,10 @@ bool token_info_set_automation_feature_from_str(TokenInfo* token_info, const Fur
|
||||
* @param src instance to clone
|
||||
* @return cloned instance
|
||||
*/
|
||||
TokenInfo* token_info_clone(const TokenInfo* src);
|
||||
TokenInfo* token_info_clone(const TokenInfo* src);
|
||||
|
||||
/**
|
||||
* @brief Sets default values to all the properties of \c token_info
|
||||
* @param token_info instance to set defaults to
|
||||
*/
|
||||
void token_info_set_defaults(TokenInfo* token_info);
|
||||
|
||||
20
applications/external/totp/ui/scene_director.c
vendored
20
applications/external/totp/ui/scene_director.c
vendored
@@ -5,29 +5,28 @@
|
||||
#include "scenes/add_new_token/totp_scene_add_new_token.h"
|
||||
#include "scenes/token_menu/totp_scene_token_menu.h"
|
||||
#include "scenes/app_settings/totp_app_settings.h"
|
||||
#include "scenes/standby/standby.h"
|
||||
|
||||
void totp_scene_director_activate_scene(
|
||||
PluginState* const plugin_state,
|
||||
Scene scene,
|
||||
const void* context) {
|
||||
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene) {
|
||||
totp_scene_director_deactivate_active_scene(plugin_state);
|
||||
switch(scene) {
|
||||
case TotpSceneGenerateToken:
|
||||
totp_scene_generate_token_activate(plugin_state, context);
|
||||
totp_scene_generate_token_activate(plugin_state);
|
||||
break;
|
||||
case TotpSceneAuthentication:
|
||||
totp_scene_authenticate_activate(plugin_state);
|
||||
break;
|
||||
case TotpSceneAddNewToken:
|
||||
totp_scene_add_new_token_activate(plugin_state, context);
|
||||
totp_scene_add_new_token_activate(plugin_state);
|
||||
break;
|
||||
case TotpSceneTokenMenu:
|
||||
totp_scene_token_menu_activate(plugin_state, context);
|
||||
totp_scene_token_menu_activate(plugin_state);
|
||||
break;
|
||||
case TotpSceneAppSettings:
|
||||
totp_scene_app_settings_activate(plugin_state, context);
|
||||
totp_scene_app_settings_activate(plugin_state);
|
||||
break;
|
||||
case TotpSceneNone:
|
||||
case TotpSceneStandby:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -56,6 +55,7 @@ void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state
|
||||
totp_scene_app_settings_deactivate(plugin_state);
|
||||
break;
|
||||
case TotpSceneNone:
|
||||
case TotpSceneStandby:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -81,6 +81,9 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_
|
||||
break;
|
||||
case TotpSceneNone:
|
||||
break;
|
||||
case TotpSceneStandby:
|
||||
totp_scene_standby_render(canvas);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -105,6 +108,7 @@ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* con
|
||||
processing = totp_scene_app_settings_handle_event(event, plugin_state);
|
||||
break;
|
||||
case TotpSceneNone:
|
||||
case TotpSceneStandby:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
* @param scene scene to be activated
|
||||
* @param context scene context to be passed to the scene activation method
|
||||
*/
|
||||
void totp_scene_director_activate_scene(
|
||||
PluginState* const plugin_state,
|
||||
Scene scene,
|
||||
const void* context);
|
||||
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene);
|
||||
|
||||
/**
|
||||
* @brief Deactivate current scene
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
#include "../../scene_director.h"
|
||||
#include "totp_input_text.h"
|
||||
#include "../../../types/token_info.h"
|
||||
#include <linked_list.h>
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../ui_controls.h"
|
||||
#include "../../common_dialogs.h"
|
||||
#include <roll_value.h>
|
||||
#include "../../../types/nullable.h"
|
||||
#include "../generate_token/totp_scene_generate_token.h"
|
||||
|
||||
char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512", "Steam"};
|
||||
char* TOKEN_DIGITS_TEXT_LIST[] = {"5 digits", "6 digits", "8 digits"};
|
||||
TokenDigitsCount TOKEN_DIGITS_VALUE_LIST[] = {TOTP_5_DIGITS, TOTP_6_DIGITS, TOTP_8_DIGITS};
|
||||
TokenDigitsCount TOKEN_DIGITS_VALUE_LIST[] = {
|
||||
TotpFiveDigitsCount,
|
||||
TotpSixDigitsCount,
|
||||
TotpEightDigitsCount};
|
||||
|
||||
typedef enum {
|
||||
TokenNameTextBox,
|
||||
@@ -36,7 +37,6 @@ typedef struct {
|
||||
InputTextSceneContext* token_secret_input_context;
|
||||
InputTextSceneState* input_state;
|
||||
uint32_t input_started_at;
|
||||
TotpNullable_uint16_t current_token_index;
|
||||
int16_t screen_y_offset;
|
||||
TokenHashAlgo algo;
|
||||
uint8_t digits_count_index;
|
||||
@@ -44,6 +44,13 @@ typedef struct {
|
||||
FuriString* duration_text;
|
||||
} SceneState;
|
||||
|
||||
struct TotpAddContext {
|
||||
SceneState* scene_state;
|
||||
uint8_t* iv;
|
||||
};
|
||||
|
||||
enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
|
||||
|
||||
static void on_token_name_user_comitted(InputTextSceneCallbackResult* result) {
|
||||
SceneState* scene_state = result->callback_data;
|
||||
free(scene_state->token_name);
|
||||
@@ -66,9 +73,29 @@ static void update_duration_text(SceneState* scene_state) {
|
||||
furi_string_printf(scene_state->duration_text, "%d sec.", scene_state->duration);
|
||||
}
|
||||
|
||||
void totp_scene_add_new_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenAddEditSceneContext* context) {
|
||||
static TotpIteratorUpdateTokenResult add_token_handler(TokenInfo* tokenInfo, const void* context) {
|
||||
const struct TotpAddContext* context_t = context;
|
||||
if(!token_info_set_secret(
|
||||
tokenInfo,
|
||||
context_t->scene_state->token_secret,
|
||||
context_t->scene_state->token_secret_length,
|
||||
PlainTokenSecretEncodingBase32,
|
||||
context_t->iv)) {
|
||||
return TotpIteratorUpdateTokenResultInvalidSecret;
|
||||
}
|
||||
|
||||
furi_string_set_strn(
|
||||
tokenInfo->name,
|
||||
context_t->scene_state->token_name,
|
||||
context_t->scene_state->token_name_length + 1);
|
||||
tokenInfo->algo = context_t->scene_state->algo;
|
||||
tokenInfo->digits = TOKEN_DIGITS_VALUE_LIST[context_t->scene_state->digits_count_index];
|
||||
tokenInfo->duration = context_t->scene_state->duration;
|
||||
|
||||
return TotpIteratorUpdateTokenResultSuccess;
|
||||
}
|
||||
|
||||
void totp_scene_add_new_token_activate(PluginState* plugin_state) {
|
||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||
furi_check(scene_state != NULL);
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
@@ -97,12 +124,6 @@ void totp_scene_add_new_token_activate(
|
||||
scene_state->duration = TOTP_TOKEN_DURATION_DEFAULT;
|
||||
scene_state->duration_text = furi_string_alloc();
|
||||
update_duration_text(scene_state);
|
||||
|
||||
if(context == NULL) {
|
||||
TOTP_NULLABLE_NULL(scene_state->current_token_index);
|
||||
} else {
|
||||
TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index);
|
||||
}
|
||||
}
|
||||
|
||||
void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||
@@ -260,38 +281,16 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
|
||||
case TokenDurationSelect:
|
||||
break;
|
||||
case ConfirmButton: {
|
||||
TokenInfo* tokenInfo = token_info_alloc();
|
||||
bool token_secret_set = token_info_set_secret(
|
||||
tokenInfo,
|
||||
scene_state->token_secret,
|
||||
scene_state->token_secret_length,
|
||||
PLAIN_TOKEN_ENCODING_BASE32,
|
||||
&plugin_state->iv[0]);
|
||||
struct TotpAddContext add_context = {
|
||||
.iv = plugin_state->iv, .scene_state = scene_state};
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(
|
||||
iterator_context, &add_token_handler, &add_context);
|
||||
|
||||
if(token_secret_set) {
|
||||
tokenInfo->name = malloc(scene_state->token_name_length + 1);
|
||||
furi_check(tokenInfo->name != NULL);
|
||||
strlcpy(
|
||||
tokenInfo->name, scene_state->token_name, scene_state->token_name_length + 1);
|
||||
tokenInfo->algo = scene_state->algo;
|
||||
tokenInfo->digits = TOKEN_DIGITS_VALUE_LIST[scene_state->digits_count_index];
|
||||
tokenInfo->duration = scene_state->duration;
|
||||
|
||||
TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);
|
||||
plugin_state->tokens_count++;
|
||||
|
||||
if(totp_config_file_save_new_token(tokenInfo) != TotpConfigFileUpdateSuccess) {
|
||||
token_info_free(tokenInfo);
|
||||
totp_dialogs_config_updating_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
GenerateTokenSceneContext generate_scene_context = {
|
||||
.current_token_index = plugin_state->tokens_count - 1};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
|
||||
} else {
|
||||
token_info_free(tokenInfo);
|
||||
if(add_result == TotpIteratorUpdateTokenResultSuccess) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultInvalidSecret) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||
dialog_message_set_text(
|
||||
@@ -305,7 +304,10 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
|
||||
dialog_message_free(message);
|
||||
scene_state->selected_control = TokenSecretTextBox;
|
||||
update_screen_y_offset(scene_state);
|
||||
} else if(add_result == TotpIteratorUpdateTokenResultFileUpdateFailed) {
|
||||
totp_dialogs_config_updating_error(plugin_state);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -313,14 +315,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(!scene_state->current_token_index.is_null) {
|
||||
GenerateTokenSceneContext generate_scene_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
|
||||
} else {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -4,13 +4,7 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} TokenAddEditSceneContext;
|
||||
|
||||
void totp_scene_add_new_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenAddEditSceneContext* context);
|
||||
void totp_scene_add_new_token_activate(PluginState* plugin_state);
|
||||
void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state);
|
||||
void totp_scene_add_new_token_deactivate(PluginState* plugin_state);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../services/convert/convert.h"
|
||||
#include <roll_value.h>
|
||||
#include "../../../types/nullable.h"
|
||||
#include "../../../features_config.h"
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||
@@ -40,21 +39,13 @@ typedef struct {
|
||||
bool badbt_enabled;
|
||||
#endif
|
||||
uint8_t y_offset;
|
||||
TotpNullable_uint16_t current_token_index;
|
||||
Control selected_control;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_app_settings_activate(
|
||||
PluginState* plugin_state,
|
||||
const AppSettingsSceneContext* context) {
|
||||
void totp_scene_app_settings_activate(PluginState* plugin_state) {
|
||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||
furi_check(scene_state != NULL);
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
if(context != NULL) {
|
||||
TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index);
|
||||
} else {
|
||||
TOTP_NULLABLE_NULL(scene_state->current_token_index);
|
||||
}
|
||||
|
||||
float off_int;
|
||||
float off_dec = modff(plugin_state->timezone_offset, &off_int);
|
||||
@@ -281,8 +272,7 @@ bool totp_scene_app_settings_handle_event(
|
||||
AutomationMethodNone;
|
||||
#endif
|
||||
|
||||
if(totp_config_file_update_user_settings(plugin_state) !=
|
||||
TotpConfigFileUpdateSuccess) {
|
||||
if(!totp_config_file_update_user_settings(plugin_state)) {
|
||||
totp_dialogs_config_updating_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
@@ -294,25 +284,11 @@ bool totp_scene_app_settings_handle_event(
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!scene_state->current_token_index.is_null) {
|
||||
TokenMenuSceneContext generate_scene_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneTokenMenu, &generate_scene_context);
|
||||
} else {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack: {
|
||||
if(!scene_state->current_token_index.is_null) {
|
||||
TokenMenuSceneContext generate_scene_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneTokenMenu, &generate_scene_context);
|
||||
} else {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -4,13 +4,7 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} AppSettingsSceneContext;
|
||||
|
||||
void totp_scene_app_settings_activate(
|
||||
PluginState* plugin_state,
|
||||
const AppSettingsSceneContext* context);
|
||||
void totp_scene_app_settings_activate(PluginState* plugin_state);
|
||||
void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state);
|
||||
bool totp_scene_app_settings_handle_event(
|
||||
const PluginEvent* const event,
|
||||
|
||||
@@ -114,12 +114,18 @@ bool totp_scene_authenticate_handle_event(
|
||||
scene_state->code_length++;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
totp_crypto_seed_iv(plugin_state, &scene_state->code_input[0], scene_state->code_length);
|
||||
case InputKeyOk: {
|
||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
|
||||
plugin_state, &scene_state->code_input[0], scene_state->code_length);
|
||||
|
||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||
totp_config_file_update_crypto_signatures(plugin_state);
|
||||
}
|
||||
|
||||
if(totp_crypto_verify_key(plugin_state)) {
|
||||
FURI_LOG_D(LOGGING_TAG, "PIN is valid");
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
} else {
|
||||
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
|
||||
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
||||
@@ -140,6 +146,7 @@ bool totp_scene_authenticate_handle_event(
|
||||
dialog_message_free(message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InputKeyBack:
|
||||
if(scene_state->code_length > 0) {
|
||||
scene_state->code_input[scene_state->code_length - 1] = 0;
|
||||
|
||||
@@ -31,9 +31,7 @@ typedef struct {
|
||||
} UiPrecalculatedDimensions;
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
|
||||
TokenInfo* current_token;
|
||||
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
||||
NotificationMessage const** notification_sequence_new_token;
|
||||
NotificationMessage const** notification_sequence_automation;
|
||||
@@ -128,19 +126,21 @@ static const NotificationSequence*
|
||||
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
||||
}
|
||||
|
||||
static void update_totp_params(PluginState* const plugin_state) {
|
||||
static void update_totp_params(PluginState* const plugin_state, size_t token_index) {
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
if(scene_state->current_token_index < plugin_state->tokens_count) {
|
||||
scene_state->current_token =
|
||||
list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(totp_token_info_iterator_go_to(iterator_context, token_index)) {
|
||||
totp_generate_code_worker_notify(
|
||||
scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) {
|
||||
uint8_t code_length = scene_state->current_token->digits;
|
||||
static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin_state) {
|
||||
const SceneState* scene_state = plugin_state->current_scene_state;
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
uint8_t code_length = totp_token_info_iterator_get_current_token(iterator_context)->digits;
|
||||
uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x;
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc;
|
||||
@@ -163,10 +163,18 @@ static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_s
|
||||
|
||||
static void on_new_token_code_generated(bool time_left, void* context) {
|
||||
const PluginState* plugin_state = context;
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SceneState* scene_state = plugin_state->current_scene_state;
|
||||
const TokenInfo* current_token = totp_token_info_iterator_get_current_token(iterator_context);
|
||||
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
scene_state->ui_precalculated_dimensions.code_total_length =
|
||||
scene_state->current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x =
|
||||
(SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x_inc =
|
||||
@@ -192,43 +200,9 @@ static void on_code_lifetime_updated_generated(float code_lifetime_percent, void
|
||||
PROGRESS_BAR_MARGIN;
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const GenerateTokenSceneContext* context) {
|
||||
if(!plugin_state->token_list_loaded) {
|
||||
TokenLoadingResult token_load_result = totp_config_file_load_tokens(plugin_state);
|
||||
if(token_load_result != TokenLoadingResultSuccess) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, NULL, "Okay", NULL);
|
||||
if(token_load_result == TokenLoadingResultWarning) {
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Unable to load some tokens\nPlease review conf file",
|
||||
SCREEN_WIDTH_CENTER,
|
||||
SCREEN_HEIGHT_CENTER,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
} else if(token_load_result == TokenLoadingResultError) {
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Unable to load tokens\nPlease review conf file",
|
||||
SCREEN_WIDTH_CENTER,
|
||||
SCREEN_HEIGHT_CENTER,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
}
|
||||
|
||||
dialog_message_show(plugin_state->dialogs_app, message);
|
||||
dialog_message_free(message);
|
||||
}
|
||||
}
|
||||
void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||
furi_check(scene_state != NULL);
|
||||
if(context == NULL || context->current_token_index > plugin_state->tokens_count) {
|
||||
scene_state->current_token_index = 0;
|
||||
} else {
|
||||
scene_state->current_token_index = context->current_token_index;
|
||||
}
|
||||
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
|
||||
@@ -254,10 +228,11 @@ void totp_scene_generate_token_activate(
|
||||
scene_state->last_code_update_sync);
|
||||
}
|
||||
#endif
|
||||
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
scene_state->generate_code_worker_context = totp_generate_code_worker_start(
|
||||
scene_state->last_code,
|
||||
&scene_state->current_token,
|
||||
totp_token_info_iterator_get_current_token(iterator_context),
|
||||
scene_state->last_code_update_sync,
|
||||
plugin_state->timezone_offset,
|
||||
plugin_state->iv);
|
||||
@@ -270,11 +245,14 @@ void totp_scene_generate_token_activate(
|
||||
&on_code_lifetime_updated_generated,
|
||||
scene_state);
|
||||
|
||||
update_totp_params(plugin_state);
|
||||
update_totp_params(
|
||||
plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context));
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||
if(plugin_state->tokens_count == 0) {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
SCREEN_WIDTH_CENTER,
|
||||
@@ -295,7 +273,9 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
|
||||
const char* token_name_cstr =
|
||||
furi_string_get_cstr(totp_token_info_iterator_get_current_token(iterator_context)->name);
|
||||
uint16_t token_name_width = canvas_string_width(canvas, token_name_cstr);
|
||||
if(SCREEN_WIDTH - token_name_width > 18) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
@@ -303,22 +283,17 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
SCREEN_HEIGHT_CENTER - 20,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
scene_state->current_token->name);
|
||||
token_name_cstr);
|
||||
} else {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
9,
|
||||
SCREEN_HEIGHT_CENTER - 20,
|
||||
AlignLeft,
|
||||
AlignCenter,
|
||||
scene_state->current_token->name);
|
||||
canvas, 9, SCREEN_HEIGHT_CENTER - 20, AlignLeft, AlignCenter, token_name_cstr);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 0, SCREEN_HEIGHT_CENTER - 24, 9, 9);
|
||||
canvas_draw_box(canvas, SCREEN_WIDTH - 10, SCREEN_HEIGHT_CENTER - 24, 9, 9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
draw_totp_code(canvas, scene_state);
|
||||
draw_totp_code(canvas, plugin_state);
|
||||
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
@@ -326,11 +301,10 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width,
|
||||
PROGRESS_BAR_HEIGHT);
|
||||
|
||||
if(plugin_state->tokens_count > 1) {
|
||||
if(totp_token_info_iterator_get_total_count(iterator_context) > 1) {
|
||||
canvas_draw_icon(canvas, 0, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_left_8x9);
|
||||
canvas_draw_icon(
|
||||
canvas, SCREEN_WIDTH - 9, 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
|
||||
@@ -351,7 +325,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
if(plugin_state->automation_method & AutomationMethodBadBt &&
|
||||
plugin_state->bt_type_code_worker_context != NULL &&
|
||||
plugin_state->bt_type_code_worker_context->is_advertising) {
|
||||
totp_bt_type_code_worker_is_advertising(plugin_state->bt_type_code_worker_context)) {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
SCREEN_WIDTH_CENTER +
|
||||
@@ -379,10 +353,12 @@ bool totp_scene_generate_token_handle_event(
|
||||
if(event->input.key == InputKeyDown &&
|
||||
plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
totp_usb_type_code_worker_notify(
|
||||
scene_state->usb_type_code_worker_context,
|
||||
TotpUsbTypeCodeWorkerEventType,
|
||||
scene_state->current_token->automation_features);
|
||||
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_automation(plugin_state, scene_state));
|
||||
@@ -393,10 +369,12 @@ bool totp_scene_generate_token_handle_event(
|
||||
event->input.key == InputKeyUp &&
|
||||
plugin_state->automation_method & AutomationMethodBadBt) {
|
||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
totp_bt_type_code_worker_notify(
|
||||
plugin_state->bt_type_code_worker_context,
|
||||
TotpBtTypeCodeWorkerEventType,
|
||||
scene_state->current_token->automation_features);
|
||||
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_automation(plugin_state, scene_state));
|
||||
@@ -409,37 +387,43 @@ bool totp_scene_generate_token_handle_event(
|
||||
return true;
|
||||
}
|
||||
|
||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
switch(event->input.key) {
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyRight:
|
||||
totp_roll_value_uint16_t(
|
||||
&scene_state->current_token_index,
|
||||
case InputKeyRight: {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
size_t current_token_index =
|
||||
totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
totp_roll_value_size_t(
|
||||
¤t_token_index,
|
||||
1,
|
||||
0,
|
||||
plugin_state->tokens_count - 1,
|
||||
totp_token_info_iterator_get_total_count(iterator_context) - 1,
|
||||
RollOverflowBehaviorRoll);
|
||||
update_totp_params(plugin_state);
|
||||
|
||||
update_totp_params(plugin_state, current_token_index);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
totp_roll_value_uint16_t(
|
||||
&scene_state->current_token_index,
|
||||
}
|
||||
case InputKeyLeft: {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
size_t current_token_index =
|
||||
totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||
totp_roll_value_size_t(
|
||||
¤t_token_index,
|
||||
-1,
|
||||
0,
|
||||
plugin_state->tokens_count - 1,
|
||||
totp_token_info_iterator_get_total_count(iterator_context) - 1,
|
||||
RollOverflowBehaviorRoll);
|
||||
update_totp_params(plugin_state);
|
||||
|
||||
update_totp_params(plugin_state, current_token_index);
|
||||
break;
|
||||
}
|
||||
case InputKeyOk:
|
||||
if(plugin_state->tokens_count == 0) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
|
||||
} else {
|
||||
TokenMenuSceneContext ctx = {.current_token_index = scene_state->current_token_index};
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &ctx);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
break;
|
||||
|
||||
@@ -4,13 +4,7 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} GenerateTokenSceneContext;
|
||||
|
||||
void totp_scene_generate_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const GenerateTokenSceneContext* context);
|
||||
void totp_scene_generate_token_activate(PluginState* plugin_state);
|
||||
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_generate_token_handle_event(
|
||||
const PluginEvent* const event,
|
||||
|
||||
12
applications/external/totp/ui/scenes/standby/standby.c
vendored
Normal file
12
applications/external/totp/ui/scenes/standby/standby.c
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "standby.h"
|
||||
#include <totp_icons.h>
|
||||
#include "../../constants.h"
|
||||
|
||||
void totp_scene_standby_render(Canvas* const canvas) {
|
||||
canvas_draw_icon(canvas, SCREEN_WIDTH - 56, SCREEN_HEIGHT - 48, &I_DolphinCommon_56x48);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 5, 10, AlignLeft, AlignTop, "CLI command");
|
||||
|
||||
canvas_draw_str_aligned(canvas, 5, 24, AlignLeft, AlignTop, "is running now");
|
||||
}
|
||||
5
applications/external/totp/ui/scenes/standby/standby.h
vendored
Normal file
5
applications/external/totp/ui/scenes/standby/standby.h
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.h>
|
||||
|
||||
void totp_scene_standby_render(Canvas* const canvas);
|
||||
@@ -6,12 +6,10 @@
|
||||
#include "../../constants.h"
|
||||
#include "../../scene_director.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include <linked_list.h>
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../generate_token/totp_scene_generate_token.h"
|
||||
#include "../add_new_token/totp_scene_add_new_token.h"
|
||||
#include "../app_settings/totp_app_settings.h"
|
||||
#include "../../../types/nullable.h"
|
||||
#include <roll_value.h>
|
||||
|
||||
#define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3)
|
||||
@@ -21,25 +19,19 @@ typedef enum { AddNewToken, DeleteToken, AppSettings } Control;
|
||||
|
||||
typedef struct {
|
||||
Control selected_control;
|
||||
TotpNullable_uint16_t current_token_index;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_token_menu_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenMenuSceneContext* context) {
|
||||
void totp_scene_token_menu_activate(PluginState* plugin_state) {
|
||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||
furi_check(scene_state != NULL);
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
if(context != NULL) {
|
||||
TOTP_NULLABLE_VALUE(scene_state->current_token_index, context->current_token_index);
|
||||
} else {
|
||||
TOTP_NULLABLE_NULL(scene_state->current_token_index);
|
||||
}
|
||||
}
|
||||
|
||||
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
if(scene_state->current_token_index.is_null) {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||
ui_control_button_render(
|
||||
canvas,
|
||||
SCREEN_WIDTH_CENTER - 36,
|
||||
@@ -95,22 +87,28 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
||||
}
|
||||
|
||||
switch(event->input.key) {
|
||||
case InputKeyUp:
|
||||
case InputKeyUp: {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
totp_roll_value_uint8_t(
|
||||
&scene_state->selected_control, -1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
||||
if(scene_state->selected_control == DeleteToken &&
|
||||
scene_state->current_token_index.is_null) {
|
||||
totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||
scene_state->selected_control--;
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
}
|
||||
case InputKeyDown: {
|
||||
const TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
totp_roll_value_uint8_t(
|
||||
&scene_state->selected_control, 1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
||||
if(scene_state->selected_control == DeleteToken &&
|
||||
scene_state->current_token_index.is_null) {
|
||||
totp_token_info_iterator_get_total_count(iterator_context) == 0) {
|
||||
scene_state->selected_control++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InputKeyRight:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
@@ -118,14 +116,7 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
||||
case InputKeyOk:
|
||||
switch(scene_state->selected_control) {
|
||||
case AddNewToken: {
|
||||
if(scene_state->current_token_index.is_null) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken, NULL);
|
||||
} else {
|
||||
TokenAddEditSceneContext add_new_token_scene_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneAddNewToken, &add_new_token_scene_context);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken);
|
||||
break;
|
||||
}
|
||||
case DeleteToken: {
|
||||
@@ -142,34 +133,21 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
||||
DialogMessageButton dialog_result =
|
||||
dialog_message_show(plugin_state->dialogs_app, message);
|
||||
dialog_message_free(message);
|
||||
TokenInfoIteratorContext* iterator_context =
|
||||
totp_config_get_token_iterator_context(plugin_state);
|
||||
if(dialog_result == DialogMessageButtonRight &&
|
||||
!scene_state->current_token_index.is_null) {
|
||||
TokenInfo* tokenInfo = NULL;
|
||||
plugin_state->tokens_list = list_remove_at(
|
||||
plugin_state->tokens_list,
|
||||
scene_state->current_token_index.value,
|
||||
(void**)&tokenInfo);
|
||||
plugin_state->tokens_count--;
|
||||
furi_check(tokenInfo != NULL);
|
||||
token_info_free(tokenInfo);
|
||||
|
||||
if(totp_full_save_config_file(plugin_state) != TotpConfigFileUpdateSuccess) {
|
||||
totp_token_info_iterator_get_total_count(iterator_context) > 0) {
|
||||
if(!totp_token_info_iterator_remove_current_token_info(iterator_context)) {
|
||||
totp_dialogs_config_updating_error(plugin_state);
|
||||
return false;
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AppSettings: {
|
||||
if(!scene_state->current_token_index.is_null) {
|
||||
AppSettingsSceneContext app_settings_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneAppSettings, &app_settings_context);
|
||||
} else {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings, NULL);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -177,14 +155,7 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
||||
}
|
||||
break;
|
||||
case InputKeyBack: {
|
||||
if(!scene_state->current_token_index.is_null) {
|
||||
GenerateTokenSceneContext generate_scene_context = {
|
||||
.current_token_index = scene_state->current_token_index.value};
|
||||
totp_scene_director_activate_scene(
|
||||
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
|
||||
} else {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -4,13 +4,7 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} TokenMenuSceneContext;
|
||||
|
||||
void totp_scene_token_menu_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenMenuSceneContext* context);
|
||||
void totp_scene_token_menu_activate(PluginState* plugin_state);
|
||||
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginState* plugin_state);
|
||||
void totp_scene_token_menu_deactivate(PluginState* plugin_state);
|
||||
|
||||
@@ -34,5 +34,10 @@ enum Scenes {
|
||||
/**
|
||||
* @brief Scene where user can change application settings
|
||||
*/
|
||||
TotpSceneAppSettings
|
||||
TotpSceneAppSettings,
|
||||
|
||||
/**
|
||||
* @brief Scene which informs user that CLI command is running
|
||||
*/
|
||||
TotpSceneStandby
|
||||
};
|
||||
|
||||
@@ -2,13 +2,39 @@
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/string.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include <storage/storage.h>
|
||||
#include "../../types/common.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../type_code_common.h"
|
||||
#include "../../features_config.h"
|
||||
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
#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
|
||||
#endif
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
|
||||
|
||||
struct TotpBtTypeCodeWorkerContext {
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
Bt* bt;
|
||||
bool is_advertising;
|
||||
bool is_connected;
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline bool totp_type_code_worker_stop_requested() {
|
||||
return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop;
|
||||
}
|
||||
@@ -197,4 +223,8 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) {
|
||||
context->bt = NULL;
|
||||
|
||||
free(context);
|
||||
}
|
||||
|
||||
bool totp_bt_type_code_worker_is_advertising(const TotpBtTypeCodeWorkerContext* context) {
|
||||
return context->is_advertising;
|
||||
}
|
||||
@@ -1,50 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/string.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include "../../features_config.h"
|
||||
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
#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
|
||||
#endif
|
||||
|
||||
typedef uint8_t TotpBtTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
Bt* bt;
|
||||
bool is_advertising;
|
||||
bool is_connected;
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
#endif
|
||||
} TotpBtTypeCodeWorkerContext;
|
||||
typedef struct TotpBtTypeCodeWorkerContext TotpBtTypeCodeWorkerContext;
|
||||
|
||||
/**
|
||||
* @brief Bluetooth token input automation worker events
|
||||
*/
|
||||
enum TotpBtTypeCodeWorkerEvents {
|
||||
|
||||
/**
|
||||
* @brief Reserved, should not be used anywhere
|
||||
*/
|
||||
TotpBtTypeCodeWorkerEventReserved = 0b00,
|
||||
|
||||
/**
|
||||
* @brief Stop worker
|
||||
*/
|
||||
TotpBtTypeCodeWorkerEventStop = 0b01,
|
||||
|
||||
/**
|
||||
* @brief Trigger token input automation
|
||||
*/
|
||||
TotpBtTypeCodeWorkerEventType = 0b10
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initializes bluetooth token input automation worker
|
||||
* @return worker context
|
||||
*/
|
||||
TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
|
||||
|
||||
/**
|
||||
* @brief Disposes bluetooth token input automation worker and releases all the allocated resources
|
||||
* @param context worker context
|
||||
*/
|
||||
void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
|
||||
|
||||
/**
|
||||
* @brief Starts bluetooth token input automation worker
|
||||
* @param context worker context
|
||||
* @param code_buffer code buffer to be used to automate
|
||||
* @param code_buffer_size code buffer size
|
||||
* @param code_buffer_sync code buffer synchronization primitive
|
||||
*/
|
||||
void totp_bt_type_code_worker_start(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
|
||||
/**
|
||||
* @brief Stops bluetooth token input automation worker
|
||||
* @param context worker context
|
||||
*/
|
||||
void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
|
||||
|
||||
/**
|
||||
* @brief Notifies bluetooth token input automation worker with a given event
|
||||
* @param context worker context
|
||||
* @param event event to notify worker with
|
||||
* @param flags event flags
|
||||
*/
|
||||
void totp_bt_type_code_worker_notify(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
TotpBtTypeCodeWorkerEvent event,
|
||||
uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Gets information whether Bluetooth is advertising now or not
|
||||
* @param context worker context
|
||||
* @return \c true if Bluetooth is advertising now; \c false otherwise
|
||||
*/
|
||||
bool totp_bt_type_code_worker_is_advertising(const TotpBtTypeCodeWorkerContext* context);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "generate_totp_code.h"
|
||||
#include <furi/core/thread.h>
|
||||
#include "../../services/crypto/crypto.h"
|
||||
#include "../../services/totp/totp.h"
|
||||
#include "../../services/convert/convert.h"
|
||||
@@ -7,6 +8,19 @@
|
||||
|
||||
#define ONE_SEC_MS (1000)
|
||||
|
||||
struct TotpGenerateCodeWorkerContext {
|
||||
char* code_buffer;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
const TokenInfo* token_info;
|
||||
float timezone_offset;
|
||||
uint8_t* iv;
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
||||
void* on_new_code_generated_handler_context;
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
||||
void* on_code_lifetime_changed_handler_context;
|
||||
};
|
||||
|
||||
static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
|
||||
static void
|
||||
@@ -93,7 +107,7 @@ static int32_t totp_generate_worker_callback(void* context) {
|
||||
|
||||
if(flags & TotpGenerateCodeWorkerEventStop) break;
|
||||
|
||||
const TokenInfo* token_info = *(t_context->token_info);
|
||||
const TokenInfo* token_info = t_context->token_info;
|
||||
if(token_info == NULL) {
|
||||
continue;
|
||||
}
|
||||
@@ -127,7 +141,7 @@ static int32_t totp_generate_worker_callback(void* context) {
|
||||
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
const TokenInfo* token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include "../../types/token_info.h"
|
||||
|
||||
@@ -10,39 +9,77 @@ typedef uint8_t TotpGenerateCodeWorkerEvent;
|
||||
typedef void (*TOTP_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context);
|
||||
typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
|
||||
|
||||
typedef struct {
|
||||
char* code_buffer;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
TokenInfo** token_info;
|
||||
float timezone_offset;
|
||||
uint8_t* iv;
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
||||
void* on_new_code_generated_handler_context;
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
||||
void* on_code_lifetime_changed_handler_context;
|
||||
} TotpGenerateCodeWorkerContext;
|
||||
typedef struct TotpGenerateCodeWorkerContext TotpGenerateCodeWorkerContext;
|
||||
|
||||
/**
|
||||
* @brief Generate token worker events
|
||||
*/
|
||||
enum TotGenerateCodeWorkerEvents {
|
||||
|
||||
/**
|
||||
* @brief Reserved, should not be used anywhere
|
||||
*/
|
||||
TotpGenerateCodeWorkerEventReserved = 0b00,
|
||||
|
||||
/**
|
||||
* @brief Stop worker
|
||||
*/
|
||||
TotpGenerateCodeWorkerEventStop = 0b01,
|
||||
|
||||
/**
|
||||
* @brief Trigger token input automation
|
||||
*/
|
||||
TotpGenerateCodeWorkerEventForceUpdate = 0b10
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Starts generate code worker
|
||||
* @param code_buffer code buffer to generate code to
|
||||
* @param token_info token info to be used to generate code
|
||||
* @param code_buffer_sync code buffer synchronization primitive
|
||||
* @param timezone_offset timezone offset to be used to generate code
|
||||
* @param iv initialization vector (IV) to be used to decrypt token secret
|
||||
* @return worker context
|
||||
*/
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
const TokenInfo* token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv);
|
||||
|
||||
/**
|
||||
* @brief Stops generate code worker
|
||||
* @param context worker context
|
||||
*/
|
||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context);
|
||||
|
||||
/**
|
||||
* @brief Notifies generate code worker with a given event
|
||||
* @param context worker context
|
||||
* @param event event to notify worker with
|
||||
*/
|
||||
void totp_generate_code_worker_notify(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TotpGenerateCodeWorkerEvent event);
|
||||
|
||||
/**
|
||||
* @brief Sets new handler for "on new code generated" event
|
||||
* @param context worker context
|
||||
* @param on_new_code_generated_handler handler
|
||||
* @param on_new_code_generated_handler_context handler context
|
||||
*/
|
||||
void totp_generate_code_worker_set_code_generated_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||
void* on_new_code_generated_handler_context);
|
||||
|
||||
/**
|
||||
* @brief Sets new handler for "on code lifetime changed" event
|
||||
* @param context worker context
|
||||
* @param on_code_lifetime_changed_handler handler
|
||||
* @param on_code_lifetime_changed_handler_context handler context
|
||||
*/
|
||||
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||
|
||||
@@ -14,7 +14,7 @@ static const uint8_t hid_number_keys[] = {
|
||||
HID_KEYBOARD_Z};
|
||||
|
||||
static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
||||
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
|
||||
if(features & TokenAutomationFeatureTypeSlower) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
||||
}
|
||||
|
||||
static uint32_t get_keypress_delay(TokenAutomationFeature features) {
|
||||
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
|
||||
if(features & TokenAutomationFeatureTypeSlower) {
|
||||
return 60;
|
||||
}
|
||||
|
||||
@@ -64,13 +64,13 @@ void totp_type_code_worker_execute_automation(
|
||||
i++;
|
||||
}
|
||||
|
||||
if(features & TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END) {
|
||||
if(features & TokenAutomationFeatureEnterAtTheEnd) {
|
||||
furi_delay_ms(get_keystroke_delay(features));
|
||||
totp_type_code_worker_press_key(
|
||||
HID_KEYBOARD_RETURN, key_press_fn, key_release_fn, features);
|
||||
}
|
||||
|
||||
if(features & TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END) {
|
||||
if(features & TokenAutomationFeatureTabAtTheEnd) {
|
||||
furi_delay_ms(get_keystroke_delay(features));
|
||||
totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
||||
|
||||
/**
|
||||
* @brief Executes token input automation using given key press\release handlers
|
||||
* @param key_press_fn key press handler
|
||||
* @param key_release_fn key release handler
|
||||
* @param code_buffer code buffer to be typed
|
||||
* @param code_buffer_size code buffer size
|
||||
* @param features automation features
|
||||
*/
|
||||
void totp_type_code_worker_execute_automation(
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
#include "usb_type_code.h"
|
||||
#include <furi_hal_usb.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <furi/core/check.h>
|
||||
#include "../../services/convert/convert.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../type_code_common.h"
|
||||
|
||||
struct TotpUsbTypeCodeWorkerContext {
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
FuriHalUsbInterface* usb_mode_prev;
|
||||
};
|
||||
|
||||
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
||||
if(context->usb_mode_prev != NULL) {
|
||||
furi_hal_usb_set_config(context->usb_mode_prev, NULL);
|
||||
|
||||
@@ -1,35 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <furi/core/check.h>
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
FuriHalUsbInterface* usb_mode_prev;
|
||||
} TotpUsbTypeCodeWorkerContext;
|
||||
typedef struct TotpUsbTypeCodeWorkerContext TotpUsbTypeCodeWorkerContext;
|
||||
|
||||
/**
|
||||
* @brief USB token input automation worker events
|
||||
*/
|
||||
enum TotpUsbTypeCodeWorkerEvents {
|
||||
|
||||
/**
|
||||
* @brief Reserved, should not be used anywhere
|
||||
*/
|
||||
TotpUsbTypeCodeWorkerEventReserved = 0b00,
|
||||
|
||||
/**
|
||||
* @brief Stop worker
|
||||
*/
|
||||
TotpUsbTypeCodeWorkerEventStop = 0b01,
|
||||
|
||||
/**
|
||||
* @brief Trigger token input automation
|
||||
*/
|
||||
TotpUsbTypeCodeWorkerEventType = 0b10
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Starts USB token input automation worker
|
||||
* @param code_buffer code buffer to be used to automate
|
||||
* @param code_buffer_size code buffer size
|
||||
* @param code_buffer_sync code buffer synchronization primitive
|
||||
* @return worker context
|
||||
*/
|
||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
|
||||
/**
|
||||
* @brief Stops USB token input automation worker
|
||||
* @param context worker context
|
||||
*/
|
||||
void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
|
||||
|
||||
/**
|
||||
* @brief Notifies USB token input automation worker with a given event
|
||||
* @param context worker context
|
||||
* @param event event to notify worker with
|
||||
* @param flags event flags
|
||||
*/
|
||||
void totp_usb_type_code_worker_notify(
|
||||
TotpUsbTypeCodeWorkerContext* context,
|
||||
TotpUsbTypeCodeWorkerEvent event,
|
||||
uint8_t flags);
|
||||
uint8_t flags);
|
||||
|
||||
Reference in New Issue
Block a user