MX
2023-04-01 17:45:52 +03:00
parent d4a20bc37a
commit 8a21b7c5a1
39 changed files with 1040 additions and 518 deletions
+8
View File
@@ -5,6 +5,7 @@
#include "cli_helpers.h"
#include "commands/list/list.h"
#include "commands/add/add.h"
#include "commands/update/update.h"
#include "commands/delete/delete.h"
#include "commands/timezone/timezone.h"
#include "commands/help/help.h"
@@ -13,6 +14,7 @@
#include "commands/notification/notification.h"
#include "commands/reset/reset.h"
#include "commands/automation/automation.h"
#include "commands/details/details.h"
static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
TOTP_CLI_PRINTF_ERROR(
@@ -62,6 +64,12 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
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);
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
totp_cli_command_update_handle(plugin_state, args, cli);
} else if(
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_DETAILS) == 0 ||
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_DETAILS_ALT) == 0) {
totp_cli_command_details_handle(plugin_state, args, cli);
} else {
totp_cli_print_unknown_command(cmd);
}
+24 -3
View File
@@ -1,19 +1,22 @@
#include "cli_helpers.h"
#include <cli/cli.h>
#include <lib/toolbox/args.h>
#include "../types/plugin_event.h"
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");
while(plugin_state->current_scene == TotpSceneAuthentication &&
while((plugin_state->current_scene == TotpSceneAuthentication ||
plugin_state->current_scene == TotpSceneNone) &&
!cli_cmd_interrupt_received(cli)) {
furi_delay_ms(100);
}
TOTP_CLI_DELETE_LAST_LINE();
if(plugin_state->current_scene == TotpSceneAuthentication) { //-V547
if(plugin_state->current_scene == TotpSceneAuthentication || //-V560
plugin_state->current_scene == TotpSceneNone) { //-V560
return false;
}
}
@@ -59,4 +62,22 @@ bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input) {
}
return true;
}
}
bool args_read_uint8_and_trim(FuriString* args, uint8_t* value) {
int int_value;
if(!args_read_int_and_trim(args, &int_value) || int_value < 0 || int_value > UINT8_MAX) {
return false;
}
*value = (uint8_t)int_value;
return true;
}
void furi_string_secure_free(FuriString* str) {
for(long i = furi_string_size(str) - 1; i >= 0; i--) {
furi_string_set_char(str, i, '\0');
}
furi_string_free(str);
}
+14
View File
@@ -89,3 +89,17 @@ void totp_cli_force_close_app(FuriMessageQueue* event_queue);
* @return \c true if line successfully read and confirmed; \c false otherwise
*/
bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input);
/**
* @brief Extracts \c uint8_t value and trims arguments string
* @param args arguments string
* @param[out] value parsed value
* @return \c true if value successfully read and parsed as \c uint8_t ; \c false otherwise
*/
bool args_read_uint8_and_trim(FuriString* args, uint8_t* value);
/**
* @brief Free \c FuriString instance in a secure manner by clearing it first
* @param str instance to free
*/
void furi_string_secure_free(FuriString* str);
+39 -108
View File
@@ -7,44 +7,7 @@
#include "../../../services/convert/convert.h"
#include "../../cli_helpers.h"
#include "../../../ui/scene_director.h"
#define TOTP_CLI_COMMAND_ADD_ARG_NAME "name"
#define TOTP_CLI_COMMAND_ADD_ARG_ALGO "algo"
#define TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX "-a"
#define TOTP_CLI_COMMAND_ADD_ARG_DIGITS "digits"
#define TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX "-d"
#define TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX "-u"
#define TOTP_CLI_COMMAND_ADD_ARG_DURATION "duration"
#define TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX "-l"
static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
token_info->algo = SHA1;
return true;
}
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME) == 0) {
token_info->algo = SHA256;
return true;
}
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME) == 0) {
token_info->algo = SHA512;
return true;
}
return false;
}
static bool args_read_uint8_and_trim(FuriString* args, uint8_t* value) {
int int_value;
if(!args_read_int_and_trim(args, &int_value) || int_value < 0 || int_value > UINT8_MAX) {
return false;
}
*value = (uint8_t)int_value;
return true;
}
#include "../../common_command_arguments.h"
void totp_cli_command_add_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD ", " TOTP_CLI_COMMAND_ADD_ALT
@@ -54,42 +17,51 @@ void totp_cli_command_add_docopt_commands() {
void totp_cli_command_add_docopt_usage() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_NAME
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_ADD " | " TOTP_CLI_COMMAND_ADD_ALT " | " TOTP_CLI_COMMAND_ADD_ALT2) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_NAME) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_ALGO))) " " DOCOPT_OPTIONAL(
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_ADD " | " TOTP_CLI_COMMAND_ADD_ALT " | " TOTP_CLI_COMMAND_ADD_ALT2) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_ALGO))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_DIGITS))) " " DOCOPT_OPTIONAL(
DOCOPT_OPTION(
TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
TOTP_CLI_COMMAND_ARG_DURATION_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ADD_ARG_DIGITS))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX)) "\r\n");
TOTP_CLI_COMMAND_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX)) " " DOCOPT_MULTIPLE(DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE)))) "\r\n");
}
void totp_cli_command_add_docopt_arguments() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD_ARG_NAME " Token name\r\n");
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ARG_NAME " Token name\r\n");
}
void totp_cli_command_add_docopt_options() {
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX,
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_ALGO)) " Token hashing algorithm.\r\n");
TOTP_CLI_PRINTF(
" Could be one of: sha1, sha256, sha512 " DOCOPT_DEFAULT("sha1") "\r\n");
cli_nl();
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
TOTP_CLI_COMMAND_ARG_ALGO_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ADD_ARG_DIGITS)) " Number of digits to generate, one of: 6, 8 " DOCOPT_DEFAULT("6") "\r\n");
TOTP_CLI_COMMAND_ARG_ALGO)) " Token hashing algorithm. Must be one of: " TOTP_TOKEN_ALGO_SHA1_NAME
", " TOTP_TOKEN_ALGO_SHA256_NAME
", " TOTP_TOKEN_ALGO_SHA512_NAME
" " DOCOPT_DEFAULT(TOTP_TOKEN_ALGO_SHA1_NAME) "\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX,
TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ADD_ARG_DURATION)) " Token lifetime duration in seconds, between: 15 and 255 " DOCOPT_DEFAULT("30") "\r\n");
TOTP_CLI_COMMAND_ARG_DIGITS)) " Number of digits to generate, one of: 6, 8 " DOCOPT_DEFAULT("6") "\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ARG_DURATION_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ARG_DURATION)) " Token lifetime duration in seconds, between: 15 and 255 " DOCOPT_DEFAULT("30") "\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_SWITCH(
TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) " Show console user input as-is without masking\r\n");
}
static void furi_string_secure_free(FuriString* str) {
for(long i = furi_string_size(str) - 1; i >= 0; i--) {
furi_string_set_char(str, i, '\0');
}
furi_string_free(str);
TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX) " Show console user input as-is without masking\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE)) " Token automation features to be enabled. Must be one of: " TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME
", " TOTP_TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END_NAME
", " TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME
" " DOCOPT_DEFAULT(
TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME) "\r\n");
TOTP_CLI_PRINTF(" # " TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME
" - No features\r\n");
TOTP_CLI_PRINTF(" # " TOTP_TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END_NAME
" - Type <Enter> key at the end of token input automation\r\n");
TOTP_CLI_PRINTF(" # " TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME
" - Type <Tab> key at the end of token input automation\r\n");
TOTP_CLI_PRINTF(" # " TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME
" - Type slower\r\n");
}
void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
@@ -113,53 +85,12 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
bool mask_user_input = true;
while(args_read_string_and_trim(args, temp_str)) {
bool parsed = false;
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX) == 0) {
if(!args_read_string_and_trim(args, temp_str)) {
TOTP_CLI_PRINTF_ERROR(
"Missed value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX "\"\r\n");
} else if(!token_info_set_algo_from_str(token_info, temp_str)) {
TOTP_CLI_PRINTF_ERROR(
"\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX
"\"\r\n",
furi_string_get_cstr(temp_str));
} else {
parsed = true;
}
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX) == 0) {
uint8_t digit_value;
if(!args_read_uint8_and_trim(args, &digit_value)) {
TOTP_CLI_PRINTF_ERROR(
"Missed or incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
"\"\r\n");
} else if(!token_info_set_digits_from_int(token_info, digit_value)) {
TOTP_CLI_PRINTF_ERROR(
"\"%" PRIu8
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
"\"\r\n",
digit_value);
} else {
parsed = true;
}
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX) == 0) {
uint8_t duration_value;
if(!args_read_uint8_and_trim(args, &duration_value)) {
TOTP_CLI_PRINTF_ERROR(
"Missed or incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX
"\"\r\n");
} else if(!token_info_set_duration_from_int(token_info, duration_value)) {
TOTP_CLI_PRINTF_ERROR(
"\"%" PRIu8
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX
"\"\r\n",
duration_value);
} else {
parsed = true;
}
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) == 0) {
mask_user_input = false;
parsed = true;
} else {
TOTP_CLI_PRINTF_ERROR("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str));
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_printf_unknown_argument(temp_str);
}
if(!parsed) {
@@ -23,12 +23,12 @@ void totp_cli_command_automation_docopt_usage() {
void totp_cli_command_automation_docopt_arguments() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD
" Automation method to be set. Must be one of [" TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE
" Automation method to be set. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB
#ifdef TOTP_BADBT_TYPE_ENABLED
", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT
#endif
"]\r\n");
"\r\n");
}
static void totp_cli_command_automation_print_method(AutomationMethod method, char* color) {
+11 -11
View File
@@ -7,9 +7,9 @@
#include "../../../services/config/config.h"
#include "../../cli_helpers.h"
#include "../../../ui/scene_director.h"
#include "../../common_command_arguments.h"
#define TOTP_CLI_COMMAND_DELETE_ARG_INDEX "index"
#define TOTP_CLI_COMMAND_DELETE_ARG_FORCE_SUFFIX "-f"
#define TOTP_CLI_COMMAND_DELETE_ARG_FORCE_PREFIX "-f"
void totp_cli_command_delete_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE ", " TOTP_CLI_COMMAND_DELETE_ALT
@@ -20,19 +20,23 @@ void totp_cli_command_delete_docopt_usage() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_NAME
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_DELETE " | " TOTP_CLI_COMMAND_DELETE_ALT) " " DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_DELETE_ARG_INDEX) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_DELETE_ARG_FORCE_SUFFIX)) "\r\n");
TOTP_CLI_COMMAND_ARG_INDEX) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_DELETE_ARG_FORCE_PREFIX)) "\r\n");
}
void totp_cli_command_delete_docopt_arguments() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE_ARG_INDEX " Token index in the list\r\n");
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ARG_INDEX " Token index in the list\r\n");
}
void totp_cli_command_delete_docopt_options() {
TOTP_CLI_PRINTF(" " DOCOPT_SWITCH(
TOTP_CLI_COMMAND_DELETE_ARG_FORCE_SUFFIX) " Force command to do not ask user for interactive confirmation\r\n");
TOTP_CLI_COMMAND_DELETE_ARG_FORCE_PREFIX) " Force command to do not ask user for interactive confirmation\r\n");
}
void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
return;
}
int token_number;
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
token_number > plugin_state->tokens_count) {
@@ -43,10 +47,10 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
FuriString* temp_str = furi_string_alloc();
bool confirm_needed = true;
if(args_read_string_and_trim(args, temp_str)) {
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_DELETE_ARG_FORCE_SUFFIX) == 0) {
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_DELETE_ARG_FORCE_PREFIX) == 0) {
confirm_needed = false;
} else {
TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str));
totp_cli_printf_unknown_argument(temp_str);
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
furi_string_free(temp_str);
return;
@@ -54,10 +58,6 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
}
furi_string_free(temp_str);
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
return;
}
ListNode* list_node = list_element_at(plugin_state->tokens_list, token_number - 1);
TokenInfo* token_info = list_node->data;
@@ -0,0 +1,78 @@
#include "details.h"
#include <stdlib.h>
#include <lib/toolbox/args.h>
#include "../../../lib/list/list.h"
#include "../../../types/token_info.h"
#include "../../../services/config/constants.h"
#include "../../cli_helpers.h"
#include "../../common_command_arguments.h"
#define TOTP_CLI_PRINTF_AUTOMATION_FEATURE(description, header_printed) \
do { \
TOTP_CLI_PRINTF( \
"| %-20s | %-28.28s |\r\n", \
header_printed ? "" : "Automation features", \
description); \
header_printed = true; \
} while(false)
static void print_automation_features(const TokenInfo* token_info) {
if(token_info->automation_features == TOKEN_AUTOMATION_FEATURE_NONE) {
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) {
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) {
TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type <Tab> key at the end", header_printed);
}
if(token_info->automation_features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type slower", header_printed);
}
}
void totp_cli_command_details_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DETAILS ", " TOTP_CLI_COMMAND_DETAILS_ALT
" Displays token details\r\n");
}
void totp_cli_command_details_docopt_usage() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " DOCOPT_REQUIRED(
TOTP_CLI_COMMAND_DETAILS
" | " TOTP_CLI_COMMAND_DETAILS_ALT) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_INDEX) "\r\n");
}
void totp_cli_command_details_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
return;
}
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();
return;
}
ListNode* list_node = list_element_at(plugin_state->tokens_list, token_number - 1);
TokenInfo* token_info = list_node->data;
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");
}
@@ -0,0 +1,11 @@
#pragma once
#include <cli/cli.h>
#include "../../../types/plugin_state.h"
#define TOTP_CLI_COMMAND_DETAILS "lsattr"
#define TOTP_CLI_COMMAND_DETAILS_ALT "cat"
void totp_cli_command_details_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
void totp_cli_command_details_docopt_commands();
void totp_cli_command_details_docopt_usage();
+8 -1
View File
@@ -1,6 +1,7 @@
#include "help.h"
#include "../../cli_helpers.h"
#include "../add/add.h"
#include "../update/update.h"
#include "../delete/delete.h"
#include "../list/list.h"
#include "../timezone/timezone.h"
@@ -9,6 +10,7 @@
#include "../notification/notification.h"
#include "../reset/reset.h"
#include "../automation/automation.h"
#include "../details/details.h"
void totp_cli_command_help_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
@@ -25,7 +27,9 @@ void totp_cli_command_help_handle() {
TOTP_CLI_PRINTF("Usage:\r\n");
totp_cli_command_help_docopt_usage();
totp_cli_command_list_docopt_usage();
totp_cli_command_details_docopt_usage();
totp_cli_command_add_docopt_usage();
totp_cli_command_update_docopt_usage();
totp_cli_command_delete_docopt_usage();
totp_cli_command_timezone_docopt_usage();
totp_cli_command_move_docopt_usage();
@@ -37,7 +41,9 @@ void totp_cli_command_help_handle() {
TOTP_CLI_PRINTF("Commands:\r\n");
totp_cli_command_help_docopt_commands();
totp_cli_command_list_docopt_commands();
totp_cli_command_details_docopt_commands();
totp_cli_command_add_docopt_commands();
totp_cli_command_update_docopt_commands();
totp_cli_command_delete_docopt_commands();
totp_cli_command_timezone_docopt_commands();
totp_cli_command_move_docopt_commands();
@@ -49,12 +55,13 @@ void totp_cli_command_help_handle() {
TOTP_CLI_PRINTF("Arguments:\r\n");
totp_cli_command_add_docopt_arguments();
totp_cli_command_delete_docopt_arguments();
totp_cli_command_move_docopt_arguments();
totp_cli_command_timezone_docopt_arguments();
totp_cli_command_notification_docopt_arguments();
totp_cli_command_automation_docopt_arguments();
cli_nl();
TOTP_CLI_PRINTF("Options:\r\n");
totp_cli_command_add_docopt_options();
totp_cli_command_update_docopt_options();
totp_cli_command_delete_docopt_options();
totp_cli_command_move_docopt_options();
}
+2 -18
View File
@@ -5,21 +5,6 @@
#include "../../../services/config/constants.h"
#include "../../cli_helpers.h"
static char* get_algo_as_cstr(TokenHashAlgo algo) {
switch(algo) {
case SHA1:
return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME;
case SHA256:
return TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME;
case SHA512:
return TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME;
default:
break;
}
return "UNKNOWN";
}
void totp_cli_command_list_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_LIST ", " TOTP_CLI_COMMAND_LIST_ALT
" List all available tokens\r\n");
@@ -41,8 +26,7 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
}
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
TOTP_CLI_PRINTF(
"| %-*s | %-*s | %-*s | %-s | %-s |\r\n", 3, "#", 25, "Name", 6, "Algo", "Ln", "Dur");
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, {
@@ -51,7 +35,7 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
"| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n",
index,
token_info->name,
get_algo_as_cstr(token_info->algo),
token_info_get_algo_as_cstr(token_info),
token_info->digits,
token_info->duration);
index++;
+23 -114
View File
@@ -7,117 +7,44 @@
#include "../../../services/config/config.h"
#include "../../cli_helpers.h"
#include "../../../ui/scene_director.h"
#include "../../common_command_arguments.h"
#define TOTP_CLI_COMMAND_MOVE_ARG_INDEX "index"
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME "name"
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX "-n"
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX "index"
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX "-i"
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX "new_index"
void totp_cli_command_move_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_MOVE ", " TOTP_CLI_COMMAND_MOVE_ALT
" Move\\rename token\r\n");
" Move token\r\n");
}
void totp_cli_command_move_docopt_usage() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_NAME
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_MOVE " | " TOTP_CLI_COMMAND_MOVE_ALT) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_INDEX) " " DOCOPT_OPTIONAL(
DOCOPT_OPTION(
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX))) "\r\n");
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_MOVE " | " TOTP_CLI_COMMAND_MOVE_ALT) " " DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ARG_INDEX) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX) "\r\n");
}
void totp_cli_command_move_docopt_options() {
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX,
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX,
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index\r\n");
void totp_cli_command_move_docopt_arguments() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX
" New token index in the list\r\n");
}
void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
int token_index;
if(!args_read_int_and_trim(args, &token_index)) {
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
return;
}
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
return;
}
if(token_index < 1 || token_index > plugin_state->tokens_count) {
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();
return;
}
FuriString* temp_str = furi_string_alloc();
char* new_token_name = NULL;
int new_token_index = 0;
while(args_read_string_and_trim(args, temp_str)) {
bool parsed = false;
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX) == 0) {
if(!args_read_string_and_trim(args, temp_str)) {
TOTP_CLI_PRINTF_ERROR(
"Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX
"\"\r\n");
} else {
if(new_token_name != NULL) {
free(new_token_name);
}
new_token_name = malloc(furi_string_size(temp_str) + 1);
if(new_token_name == NULL) {
furi_string_free(temp_str);
return;
}
strlcpy(
new_token_name,
furi_string_get_cstr(temp_str),
furi_string_size(temp_str) + 1);
parsed = true;
}
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX) == 0) {
if(!args_read_int_and_trim(args, &new_token_index)) {
TOTP_CLI_PRINTF_ERROR(
"Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX
"\"\r\n");
} else if(new_token_index < 1 || new_token_index > plugin_state->tokens_count) {
TOTP_CLI_PRINTF_ERROR(
"\"%" PRId16
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX
"\"\r\n",
new_token_index);
} else {
parsed = true;
}
} else {
TOTP_CLI_PRINTF_ERROR("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str));
}
if(!parsed) {
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
furi_string_free(temp_str);
if(new_token_name != NULL) {
free(new_token_name);
}
return;
}
}
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
furi_string_free(temp_str);
if(new_token_name != NULL) {
free(new_token_name);
}
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();
return;
}
@@ -127,39 +54,21 @@ void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, C
activate_generate_token_scene = true;
}
bool token_updated = false;
TokenInfo* token_info = NULL;
if(new_token_index > 0) {
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);
token_updated = true;
} else {
token_info = list_element_at(plugin_state->tokens_list, token_index - 1)->data;
}
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);
if(new_token_name != NULL) {
free(token_info->name);
token_info->name = new_token_name;
token_updated = true;
}
if(token_updated) {
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
TOTP_CLI_PRINTF_SUCCESS(
"Token \"%s\" has been successfully updated\r\n", token_info->name);
} else {
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
}
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
TOTP_CLI_PRINTF_SUCCESS(
"Token \"%s\" has been successfully updated\r\n", token_info->name);
} else {
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
}
if(activate_generate_token_scene) {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
furi_string_free(temp_str);
}
+1 -1
View File
@@ -9,4 +9,4 @@
void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
void totp_cli_command_move_docopt_commands();
void totp_cli_command_move_docopt_usage();
void totp_cli_command_move_docopt_options();
void totp_cli_command_move_docopt_arguments();
@@ -23,9 +23,9 @@ void totp_cli_command_notification_docopt_usage() {
void totp_cli_command_notification_docopt_arguments() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD
" Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE
" Notification method to be set. Must be one of: " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE
", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND
", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "]\r\n");
", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "\r\n");
}
static void totp_cli_command_notification_print_method(NotificationMethod method, char* color) {
+162
View File
@@ -0,0 +1,162 @@
#include "update.h"
#include <stdlib.h>
#include <lib/toolbox/args.h>
#include "../../../lib/list/list.h"
#include "../../../types/token_info.h"
#include "../../../services/config/config.h"
#include "../../../services/convert/convert.h"
#include "../../cli_helpers.h"
#include "../../../ui/scene_director.h"
#include "../../common_command_arguments.h"
#define TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX "-s"
void totp_cli_command_update_docopt_commands() {
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_UPDATE " Update existing token\r\n");
}
void totp_cli_command_update_docopt_usage() {
TOTP_CLI_PRINTF(
" " TOTP_CLI_COMMAND_NAME
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_UPDATE) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_INDEX) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_ALGO))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_NAME_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME))) " " DOCOPT_OPTIONAL(
DOCOPT_OPTION(
TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX,
DOCOPT_ARGUMENT(
TOTP_CLI_COMMAND_ARG_DIGITS))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX)) " " DOCOPT_MULTIPLE(DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE)))) "\r\n");
}
void totp_cli_command_update_docopt_options() {
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ARG_NAME_PREFIX,
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME)) " Token name\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;
}
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();
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);
// Read optional arguments
bool mask_user_input = true;
bool update_token_secret = false;
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_printf_unknown_argument(temp_str);
}
if(!parsed) {
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
furi_string_free(temp_str);
token_info_free(token_info);
return;
}
}
if(update_token_secret) {
// 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();
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();
if(token_info->token != NULL) {
free(token_info->token);
}
if(!token_info_set_secret(
token_info,
furi_string_get_cstr(temp_str),
furi_string_size(temp_str),
plugin_state->iv)) {
TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n");
furi_string_secure_free(temp_str);
token_info_free(token_info);
return;
}
}
furi_string_secure_free(temp_str);
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;
}
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);
}
if(load_generate_token_scene) {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <cli/cli.h>
#include "../../../types/plugin_state.h"
#define TOTP_CLI_COMMAND_UPDATE "update"
void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
void totp_cli_command_update_docopt_commands();
void totp_cli_command_update_docopt_usage();
void totp_cli_command_update_docopt_options();
@@ -0,0 +1,112 @@
#include "common_command_arguments.h"
#include <lib/toolbox/args.h>
inline 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) {
TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(arg));
}
bool totp_cli_try_read_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed) {
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_ALGO_PREFIX) == 0) {
if(!args_read_string_and_trim(args, arg)) {
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_ALGO_PREFIX);
} else if(!token_info_set_algo_from_str(token_info, arg)) {
TOTP_CLI_PRINTF_ERROR(
"\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ARG_ALGO_PREFIX
"\"\r\n",
furi_string_get_cstr(arg));
} else {
*parsed = true;
}
return true;
}
return false;
}
bool totp_cli_try_read_digits(
TokenInfo* token_info,
const FuriString* arg,
FuriString* args,
bool* parsed) {
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX) == 0) {
uint8_t digit_value;
if(!args_read_uint8_and_trim(args, &digit_value)) {
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX);
} else if(!token_info_set_digits_from_int(token_info, digit_value)) {
TOTP_CLI_PRINTF_ERROR(
"\"%" PRIu8
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX
"\"\r\n",
digit_value);
} else {
*parsed = true;
}
return true;
}
return false;
}
bool totp_cli_try_read_duration(
TokenInfo* token_info,
const FuriString* arg,
FuriString* args,
bool* parsed) {
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_DURATION_PREFIX) == 0) {
uint8_t duration_value;
if(!args_read_uint8_and_trim(args, &duration_value)) {
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_DURATION_PREFIX);
} else if(!token_info_set_duration_from_int(token_info, duration_value)) {
TOTP_CLI_PRINTF_ERROR(
"\"%" PRIu8
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ARG_DURATION_PREFIX
"\"\r\n",
duration_value);
} else {
*parsed = true;
}
return true;
}
return false;
}
bool totp_cli_try_read_automation_features(
TokenInfo* token_info,
FuriString* arg,
FuriString* args,
bool* parsed) {
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX) == 0) {
if(!args_read_string_and_trim(args, arg)) {
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX);
} else if(!token_info_set_automation_feature_from_str(token_info, arg)) {
TOTP_CLI_PRINTF_ERROR(
"\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX
"\"\r\n",
furi_string_get_cstr(arg));
} else {
*parsed = true;
}
return true;
}
return false;
}
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag) {
if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX) == 0) {
*unsecure_flag = false;
*parsed = true;
return true;
}
return false;
}
@@ -0,0 +1,37 @@
#pragma once
#include <stdlib.h>
#include "../types/token_info.h"
#include "cli_helpers.h"
#define TOTP_CLI_COMMAND_ARG_NAME "name"
#define TOTP_CLI_COMMAND_ARG_NAME_PREFIX "-n"
#define TOTP_CLI_COMMAND_ARG_ALGO "algo"
#define TOTP_CLI_COMMAND_ARG_ALGO_PREFIX "-a"
#define TOTP_CLI_COMMAND_ARG_DIGITS "digits"
#define TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX "-d"
#define TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX "-u"
#define TOTP_CLI_COMMAND_ARG_DURATION "duration"
#define TOTP_CLI_COMMAND_ARG_DURATION_PREFIX "-l"
#define TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX "-b"
#define TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE "feature"
#define TOTP_CLI_COMMAND_ARG_INDEX "index"
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);
+1 -1
View File
@@ -1,2 +1,2 @@
#define TOTP_BADBT_TYPE_ENABLED
#define TOTP_BADBT_TYPE_ICON_ENABLED
#define TOTP_AUTOMATION_ICONS_ENABLED
Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

+42 -57
View File
@@ -5,8 +5,7 @@
#include "../../types/common.h"
#include "../../types/token_info.h"
#include "../../features_config.h"
#include "migrations/config_migration_v1_to_v2.h"
#include "migrations/config_migration_v2_to_v3.h"
#include "migrations/common_migration.h"
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
@@ -15,31 +14,6 @@
#define CONFIG_FILE_ORIG_PATH CONFIG_FILE_PATH ".orig"
#define CONFIG_FILE_PATH_PREVIOUS EXT_PATH("apps/Misc") "/totp.conf"
static char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
switch(token_info->algo) {
case SHA1:
return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME;
case SHA256:
return TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME;
case SHA512:
return TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME;
default:
break;
}
return NULL;
}
static void token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
token_info->algo = SHA1;
} else if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME) == 0) {
token_info->algo = SHA256;
} else if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME) == 0) {
token_info->algo = SHA512;
}
}
/**
* @brief Opens storage record
* @return Storage record
@@ -166,13 +140,13 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF
furi_string_printf(
temp_str,
" # Token hashing algorithm to use during code generation. Supported options are %s, %s and %s. If you are not use which one to use - use %s",
TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
TOTP_TOKEN_ALGO_SHA1_NAME,
TOTP_TOKEN_ALGO_SHA256_NAME,
TOTP_TOKEN_ALGO_SHA512_NAME,
TOTP_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str);
furi_string_printf(
temp_str, "%s: %s", TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
temp_str, "%s: %s", TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
@@ -190,6 +164,13 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(
fff_data_file,
"# Token input automation features (0 - None, 1 - press \"Enter\" key at the end of automation)");
furi_string_printf(temp_str, "%s: 0", TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE END ===");
flipper_format_write_comment_cstr(fff_data_file, " ");
@@ -255,6 +236,13 @@ static TotpConfigFileUpdateResult
break;
}
tmp_uint32 = token_info->automation_features;
if(!flipper_format_write_uint32(
file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, &tmp_uint32, 1)) {
update_result = TotpConfigFileUpdateError;
break;
}
update_result = TotpConfigFileUpdateSuccess;
} while(false);
@@ -544,28 +532,19 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st
break;
}
if(file_version == 1) {
if(totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
file_version = 2;
} else {
FURI_LOG_W(
LOGGING_TAG, "An error occurred during migration from v1 to v2");
result = TotpConfigFileOpenError;
break;
}
}
if(file_version == 2) {
if(totp_config_migrate_v2_to_v3(fff_data_file, fff_backup_data_file)) {
FURI_LOG_I(LOGGING_TAG, "Applied migration from v2 to v3");
file_version = 3;
} else {
FURI_LOG_W(
LOGGING_TAG, "An error occurred during migration from v2 to v3");
result = TotpConfigFileOpenError;
break;
}
if(totp_config_migrate_to_latest(fff_data_file, fff_backup_data_file)) {
FURI_LOG_I(
LOGGING_TAG,
"Applied migration to version %" PRId16,
CONFIG_FILE_ACTUAL_VERSION);
file_version = CONFIG_FILE_ACTUAL_VERSION;
} else {
FURI_LOG_W(
LOGGING_TAG,
"An error occurred during migration to version %" PRId16,
CONFIG_FILE_ACTUAL_VERSION);
result = TotpConfigFileOpenError;
break;
}
flipper_format_file_close(fff_backup_data_file);
@@ -743,9 +722,8 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
}
}
if(flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str)) {
token_info_set_algo_from_str(tokenInfo, temp_str);
} else {
if(!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str) ||
!token_info_set_algo_from_str(tokenInfo, temp_str)) {
tokenInfo->algo = SHA1;
}
@@ -761,6 +739,13 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
}
if(flipper_format_read_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, &temp_data32, 1)) {
tokenInfo->automation_features = temp_data32;
} else {
tokenInfo->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
}
FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name);
TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);
+2 -5
View File
@@ -1,7 +1,7 @@
#pragma once
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
#define CONFIG_FILE_ACTUAL_VERSION 3
#define CONFIG_FILE_ACTUAL_VERSION 4
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
@@ -9,12 +9,9 @@
#define TOTP_CONFIG_KEY_TOKEN_ALGO "TokenAlgo"
#define TOTP_CONFIG_KEY_TOKEN_DIGITS "TokenDigits"
#define TOTP_CONFIG_KEY_TOKEN_DURATION "TokenDuration"
#define TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES "TokenAutomationFeatures"
#define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
#define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"
#define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
#define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1"
#define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256"
#define TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME "sha512"
@@ -0,0 +1,129 @@
#include "common_migration.h"
#include "../constants.h"
#include "../../../types/token_info.h"
bool totp_config_migrate_to_latest(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file) {
FuriString* temp_str = furi_string_alloc();
uint32_t current_version = 0;
bool result = false;
do {
flipper_format_write_header_cstr(
fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
if(!flipper_format_read_header(fff_backup_data_file, temp_str, &current_version)) {
break;
}
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_PINSET, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_PINSET, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str)) {
flipper_format_write_string(
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, temp_str)) {
flipper_format_write_string(
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, temp_str);
}
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(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
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);
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;
flipper_format_write_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
}
if(current_version > 2) {
flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, temp_str);
flipper_format_write_string(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, temp_str);
} else {
const uint32_t default_duration = TOTP_TOKEN_DURATION_DEFAULT;
flipper_format_write_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, &default_duration, 1);
}
if(current_version > 3) {
flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, temp_str);
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;
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);
result = true;
} while(false);
furi_string_free(temp_str);
return result;
}
@@ -2,6 +2,6 @@
#include <flipper_format/flipper_format.h>
bool totp_config_migrate_v2_to_v3(
bool totp_config_migrate_to_latest(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file);
FlipperFormat* fff_backup_data_file);
@@ -1,47 +0,0 @@
#include "config_migration_v1_to_v2.h"
#include <flipper_format/flipper_format.h>
#include "../constants.h"
#include "../../../types/token_info.h"
#define NEW_VERSION 2
bool totp_config_migrate_v1_to_v2(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file) {
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION);
FuriString* temp_str = furi_string_alloc();
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
}
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
}
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
}
while(true) {
if(!flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break;
}
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string_cstr(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
const uint32_t default_digits = TOTP_6_DIGITS;
flipper_format_write_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
}
furi_string_free(temp_str);
return true;
}
@@ -1,7 +0,0 @@
#pragma once
#include <flipper_format/flipper_format.h>
bool totp_config_migrate_v1_to_v2(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file);
@@ -1,70 +0,0 @@
#include "config_migration_v2_to_v3.h"
#include <flipper_format/flipper_format.h>
#include "../constants.h"
#include "../../../types/token_info.h"
#define NEW_VERSION 3
bool totp_config_migrate_v2_to_v3(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file) {
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION);
FuriString* temp_str = furi_string_alloc();
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_PINSET, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_PINSET, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
if(flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str);
}
flipper_format_rewind(fff_backup_data_file);
while(true) {
if(!flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break;
}
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
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);
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);
const uint32_t default_duration = TOTP_TOKEN_DURATION_DEFAULT;
flipper_format_write_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, &default_duration, 1);
}
furi_string_free(temp_str);
return true;
}
+76 -1
View File
@@ -1,4 +1,3 @@
#include <furi/furi.h>
#include <furi_hal.h>
#include "token_info.h"
#include "stdlib.h"
@@ -6,6 +5,7 @@
#include "../lib/base32/base32.h"
#include "../services/crypto/crypto.h"
#include "../lib/polyfills/memset_s.h"
#include "../lib/polyfills/strnlen.h"
TokenInfo* token_info_alloc() {
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
@@ -13,6 +13,7 @@ TokenInfo* token_info_alloc() {
tokenInfo->algo = SHA1;
tokenInfo->digits = TOTP_6_DIGITS;
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
tokenInfo->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
return tokenInfo;
}
@@ -70,4 +71,78 @@ bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration) {
}
return false;
}
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
if(furi_string_cmpi_str(str, TOTP_TOKEN_ALGO_SHA1_NAME) == 0) {
token_info->algo = SHA1;
return true;
}
if(furi_string_cmpi_str(str, TOTP_TOKEN_ALGO_SHA256_NAME) == 0) {
token_info->algo = SHA256;
return true;
}
if(furi_string_cmpi_str(str, TOTP_TOKEN_ALGO_SHA512_NAME) == 0) {
token_info->algo = SHA512;
return true;
}
return false;
}
char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
switch(token_info->algo) {
case SHA1:
return TOTP_TOKEN_ALGO_SHA1_NAME;
case SHA256:
return TOTP_TOKEN_ALGO_SHA256_NAME;
case SHA512:
return TOTP_TOKEN_ALGO_SHA512_NAME;
default:
break;
}
return NULL;
}
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;
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;
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;
return true;
}
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME) == 0) {
token_info->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
return true;
}
return false;
}
TokenInfo* token_info_clone(const TokenInfo* src) {
TokenInfo* clone = token_info_alloc();
memcpy(clone, src, sizeof(TokenInfo));
clone->token = malloc(src->token_length);
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);
return clone;
}
+73
View File
@@ -1,11 +1,24 @@
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <furi/furi.h>
#define TOTP_TOKEN_DURATION_DEFAULT 30
#define TOTP_TOKEN_ALGO_SHA1_NAME "sha1"
#define TOTP_TOKEN_ALGO_SHA256_NAME "sha256"
#define TOTP_TOKEN_ALGO_SHA512_NAME "sha512"
#define TOTP_TOKEN_MAX_LENGTH 255
#define TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME "none"
#define TOTP_TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END_NAME "enter"
#define TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME "tab"
#define TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME "slower"
typedef uint8_t TokenHashAlgo;
typedef uint8_t TokenDigitsCount;
typedef uint8_t TokenAutomationFeature;
/**
* @brief Hashing algorithm to be used to generate token
@@ -42,6 +55,31 @@ enum TokenDigitsCounts {
TOTP_8_DIGITS = 8
};
/**
* @brief Token automation features.
*/
enum TokenAutomationFeatures {
/**
* @brief No features enabled
*/
TOKEN_AUTOMATION_FEATURE_NONE = 0b000,
/**
* @brief Press "Enter" key at the end as a part of token input automation
*/
TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END = 0b001,
/**
* @brief Press "Tab" key at the end as a part of token input automation
*/
TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END = 0b010,
/**
* @brief Press keys slower and wait longer between keystrokes
*/
TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER = 0b100
};
#define TOTP_TOKEN_DIGITS_MAX_COUNT 8
/**
@@ -77,6 +115,11 @@ typedef struct {
* @brief Desired TOTP token duration in seconds
*/
uint8_t duration;
/**
* @brief Token input automation features
*/
TokenAutomationFeature automation_features;
} TokenInfo;
/**
@@ -120,3 +163,33 @@ bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits);
* @return \c true if token duration has been updated; \c false otherwise
*/
bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration);
/**
* @brief Sets token hashing algorithm from \c str value
* @param token_info instance whichs token hashing algorithm should be updated
* @param str desired token algorithm
* @return \c true if token hahsing algorithm has been updated; \c false otherwise
*/
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str);
/**
* @brief Gets token hahsing algorithm name as C-string
* @param token_info instance which token hahsing algorithm name should be returned
* @return token hashing algorithm name as C-string
*/
char* token_info_get_algo_as_cstr(const TokenInfo* token_info);
/**
* @brief Sets token automation feature from \c str value
* @param token_info instance whichs token automation feature should be updated
* @param str desired token automation feature
* @return \c true if token automation feature has been set; \c false otherwise
*/
bool token_info_set_automation_feature_from_str(TokenInfo* token_info, const FuriString* str);
/**
* @brief Clones \c TokenInfo instance
* @param src instance to clone
* @return cloned instance
*/
TokenInfo* token_info_clone(const TokenInfo* src);
@@ -350,14 +350,34 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
canvas, SCREEN_WIDTH - 9, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9);
}
#if defined(TOTP_BADBT_TYPE_ENABLED) && defined(TOTP_BADBT_TYPE_ICON_ENABLED)
#ifdef TOTP_AUTOMATION_ICONS_ENABLED
if(plugin_state->automation_method & AutomationMethodBadUsb) {
canvas_draw_icon(
canvas,
#ifdef TOTP_BADBT_TYPE_ENABLED
SCREEN_WIDTH_CENTER -
(plugin_state->automation_method & AutomationMethodBadBt ? 33 : 15),
#else
SCREEN_WIDTH_CENTER - 15,
#endif
SCREEN_HEIGHT_CENTER + 12,
&I_hid_usb_31x9);
}
#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) {
canvas_draw_icon(
canvas, SCREEN_WIDTH_CENTER - 5, SCREEN_HEIGHT_CENTER + 13, &I_hid_ble_10x7);
canvas,
SCREEN_WIDTH_CENTER +
(plugin_state->automation_method & AutomationMethodBadUsb ? 2 : -15),
SCREEN_HEIGHT_CENTER + 12,
&I_hid_ble_31x9);
}
#endif
#endif
}
bool totp_scene_generate_token_handle_event(
@@ -377,7 +397,9 @@ bool totp_scene_generate_token_handle_event(
plugin_state->automation_method & AutomationMethodBadUsb) {
scene_state = (SceneState*)plugin_state->current_scene_state;
totp_usb_type_code_worker_notify(
scene_state->usb_type_code_worker_context, TotpUsbTypeCodeWorkerEventType);
scene_state->usb_type_code_worker_context,
TotpUsbTypeCodeWorkerEventType,
scene_state->current_token->automation_features);
notification_message(
plugin_state->notification_app,
get_notification_sequence_automation(plugin_state, scene_state));
@@ -389,7 +411,9 @@ bool totp_scene_generate_token_handle_event(
plugin_state->automation_method & AutomationMethodBadBt) {
scene_state = (SceneState*)plugin_state->current_scene_state;
totp_bt_type_code_worker_notify(
plugin_state->bt_type_code_worker_context, TotpBtTypeCodeWorkerEventType);
plugin_state->bt_type_code_worker_context,
TotpBtTypeCodeWorkerEventType,
scene_state->current_token->automation_features);
notification_message(
plugin_state->notification_app,
get_notification_sequence_automation(plugin_state, scene_state));
@@ -2,8 +2,8 @@
#include <furi_hal_bt_hid.h>
#include <storage/storage.h>
#include "../../types/common.h"
#include "../../services/convert/convert.h"
#include "../constants.h"
#include "../../types/token_info.h"
#include "../common.h"
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
@@ -16,21 +16,15 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
do {
furi_delay_ms(500);
i++;
} while(!furi_hal_bt_is_active() && i < 100 && !totp_type_code_worker_stop_requested());
if(furi_hal_bt_is_active() && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
furi_delay_ms(500);
i = 0;
while(i < context->string_length && context->string[i] != 0) {
uint8_t digit = CONVERT_CHAR_TO_DIGIT(context->string[i]);
if(digit > 9) break;
uint8_t hid_kb_key = hid_number_keys[digit];
furi_hal_bt_hid_kb_press(hid_kb_key);
furi_delay_ms(30);
furi_hal_bt_hid_kb_release(hid_kb_key);
i++;
}
} while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested());
if(context->is_connected && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
totp_type_code_worker_execute_automation(
&furi_hal_bt_hid_kb_press,
&furi_hal_bt_hid_kb_release,
context->string,
context->string_length,
context->flags);
furi_mutex_release(context->string_sync);
}
}
@@ -44,9 +38,6 @@ static int32_t totp_type_code_worker_callback(void* context) {
TotpBtTypeCodeWorkerContext* bt_context = context;
furi_hal_bt_start_advertising();
bt_context->is_advertising = true;
while(true) {
uint32_t flags = furi_thread_flags_wait(
TotpBtTypeCodeWorkerEventStop | TotpBtTypeCodeWorkerEventType,
@@ -64,15 +55,20 @@ static int32_t totp_type_code_worker_callback(void* context) {
}
}
furi_hal_bt_stop_advertising();
bt_context->is_advertising = false;
furi_mutex_free(context_mutex);
return 0;
}
static void connection_status_changed_callback(BtStatus status, void* context) {
TotpBtTypeCodeWorkerContext* bt_context = context;
if(status == BtStatusConnected) {
bt_context->is_connected = true;
} else if(status < BtStatusConnected) {
bt_context->is_connected = false;
}
}
void totp_bt_type_code_worker_start(
TotpBtTypeCodeWorkerContext* context,
char* code_buf,
@@ -100,8 +96,10 @@ void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context) {
void totp_bt_type_code_worker_notify(
TotpBtTypeCodeWorkerContext* context,
TotpBtTypeCodeWorkerEvent event) {
TotpBtTypeCodeWorkerEvent event,
uint8_t flags) {
furi_assert(context != NULL);
context->flags = flags;
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
}
@@ -111,13 +109,19 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
context->bt = furi_record_open(RECORD_BT);
context->is_advertising = false;
context->is_connected = false;
bt_disconnect(context->bt);
furi_hal_bt_reinit();
furi_delay_ms(200);
bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH);
if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) {
FURI_LOG_E(LOGGING_TAG, "Failed to switch BT to keyboard HID profile");
}
furi_hal_bt_start_advertising();
context->is_advertising = true;
bt_set_status_changed_callback(context->bt, connection_status_changed_callback, context);
return context;
}
@@ -128,7 +132,14 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) {
totp_bt_type_code_worker_stop(context);
}
bt_set_status_changed_callback(context->bt, NULL, NULL);
furi_hal_bt_stop_advertising();
context->is_advertising = false;
context->is_connected = false;
bt_disconnect(context->bt);
furi_delay_ms(200);
bt_keys_storage_set_default_path(context->bt);
if(!bt_set_profile(context->bt, BtProfileSerial)) {
@@ -10,16 +10,18 @@ typedef uint8_t TotpBtTypeCodeWorkerEvent;
typedef struct {
char* string;
uint8_t string_length;
uint8_t flags;
FuriThread* thread;
FuriMutex* string_sync;
Bt* bt;
bool is_advertising;
bool is_connected;
} TotpBtTypeCodeWorkerContext;
enum TotpBtTypeCodeWorkerEvents {
TotpBtTypeCodeWorkerEventReserved = (1 << 0),
TotpBtTypeCodeWorkerEventStop = (1 << 1),
TotpBtTypeCodeWorkerEventType = (1 << 2)
TotpBtTypeCodeWorkerEventReserved = 0b0000,
TotpBtTypeCodeWorkerEventStop = 0b0100,
TotpBtTypeCodeWorkerEventType = 0b1000
};
TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
@@ -32,4 +34,5 @@ void totp_bt_type_code_worker_start(
void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
void totp_bt_type_code_worker_notify(
TotpBtTypeCodeWorkerContext* context,
TotpBtTypeCodeWorkerEvent event);
TotpBtTypeCodeWorkerEvent event,
uint8_t flags);
+71
View File
@@ -0,0 +1,71 @@
#include "common.h"
#include <furi/furi.h>
#include <furi_hal.h>
#include "../../services/convert/convert.h"
static const uint8_t hid_number_keys[10] = {
HID_KEYBOARD_0,
HID_KEYBOARD_1,
HID_KEYBOARD_2,
HID_KEYBOARD_3,
HID_KEYBOARD_4,
HID_KEYBOARD_5,
HID_KEYBOARD_6,
HID_KEYBOARD_7,
HID_KEYBOARD_8,
HID_KEYBOARD_9};
static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
return 100;
}
return 30;
}
static uint32_t get_keypress_delay(TokenAutomationFeature features) {
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
return 60;
}
return 30;
}
static void totp_type_code_worker_press_key(
uint8_t key,
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
TokenAutomationFeature features) {
(*key_press_fn)(key);
furi_delay_ms(get_keypress_delay(features));
(*key_release_fn)(key);
}
void totp_type_code_worker_execute_automation(
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
const char* string,
uint8_t string_length,
TokenAutomationFeature features) {
furi_delay_ms(500);
uint8_t i = 0;
while(i < string_length && string[i] != 0) {
uint8_t digit = CONVERT_CHAR_TO_DIGIT(string[i]);
if(digit > 9) break;
uint8_t hid_kb_key = hid_number_keys[digit];
totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features);
furi_delay_ms(get_keystroke_delay(features));
i++;
}
if(features & TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END) {
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) {
furi_delay_ms(get_keystroke_delay(features));
totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features);
}
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#include "../types/token_info.h"
typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
void totp_type_code_worker_execute_automation(
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
const char* string,
uint8_t string_length,
TokenAutomationFeature features);
-14
View File
@@ -1,14 +0,0 @@
#include "constants.h"
#include <furi_hal.h>
const uint8_t hid_number_keys[10] = {
HID_KEYBOARD_0,
HID_KEYBOARD_1,
HID_KEYBOARD_2,
HID_KEYBOARD_3,
HID_KEYBOARD_4,
HID_KEYBOARD_5,
HID_KEYBOARD_6,
HID_KEYBOARD_7,
HID_KEYBOARD_8,
HID_KEYBOARD_9};
-4
View File
@@ -1,4 +0,0 @@
#pragma once
#include <stdint.h>
extern const uint8_t hid_number_keys[10];
@@ -1,6 +1,7 @@
#include "usb_type_code.h"
#include "../../services/convert/convert.h"
#include "../constants.h"
#include "../../types/token_info.h"
#include "../common.h"
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
if(context->usb_mode_prev != NULL) {
@@ -25,18 +26,12 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
if(furi_hal_hid_is_connected() &&
furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
furi_delay_ms(500);
i = 0;
while(i < context->string_length && context->string[i] != 0) {
uint8_t digit = CONVERT_CHAR_TO_DIGIT(context->string[i]);
if(digit > 9) break;
uint8_t hid_kb_key = hid_number_keys[digit];
furi_hal_hid_kb_press(hid_kb_key);
furi_delay_ms(30);
furi_hal_hid_kb_release(hid_kb_key);
i++;
}
totp_type_code_worker_execute_automation(
&furi_hal_hid_kb_press,
&furi_hal_hid_kb_release,
context->string,
context->string_length,
context->flags);
furi_mutex_release(context->string_sync);
furi_delay_ms(100);
@@ -104,7 +99,9 @@ void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context) {
void totp_usb_type_code_worker_notify(
TotpUsbTypeCodeWorkerContext* context,
TotpUsbTypeCodeWorkerEvent event) {
TotpUsbTypeCodeWorkerEvent event,
uint8_t flags) {
furi_assert(context != NULL);
context->flags = flags;
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
}
@@ -9,15 +9,16 @@ typedef uint8_t TotpUsbTypeCodeWorkerEvent;
typedef struct {
char* string;
uint8_t string_length;
uint8_t flags;
FuriThread* thread;
FuriMutex* string_sync;
FuriHalUsbInterface* usb_mode_prev;
} TotpUsbTypeCodeWorkerContext;
enum TotpUsbTypeCodeWorkerEvents {
TotpUsbTypeCodeWorkerEventReserved = (1 << 0),
TotpUsbTypeCodeWorkerEventStop = (1 << 1),
TotpUsbTypeCodeWorkerEventType = (1 << 2)
TotpUsbTypeCodeWorkerEventReserved = 0b00,
TotpUsbTypeCodeWorkerEventStop = 0b01,
TotpUsbTypeCodeWorkerEventType = 0b10
};
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
@@ -27,4 +28,5 @@ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
void totp_usb_type_code_worker_notify(
TotpUsbTypeCodeWorkerContext* context,
TotpUsbTypeCodeWorkerEvent event);
TotpUsbTypeCodeWorkerEvent event,
uint8_t flags);