Skip to content

Commit

Permalink
Implemented #95 (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
akopachov committed Mar 30, 2023
1 parent 03a7f93 commit fd60525
Show file tree
Hide file tree
Showing 36 changed files with 914 additions and 420 deletions.
8 changes: 8 additions & 0 deletions cli/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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(
Expand Down Expand Up @@ -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);
}
Expand Down
21 changes: 20 additions & 1 deletion cli/cli_helpers.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#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) {
Expand Down Expand Up @@ -59,4 +60,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 changes: 14 additions & 0 deletions cli/cli_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
140 changes: 33 additions & 107 deletions cli/commands/add/add.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -54,42 +17,46 @@ 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_COMMAND_ARG_ALGO_PREFIX,
DOCOPT_ARGUMENT(
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_DIGITS_PREFIX,
TOTP_CLI_COMMAND_ARG_DIGITS_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_DIGITS)) " Number of digits to generate, one of: 6, 8 " DOCOPT_DEFAULT("6") "\r\n");
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX,
TOTP_CLI_COMMAND_ARG_DURATION_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_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
" " 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");
}

void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
Expand All @@ -113,53 +80,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) {
Expand Down
4 changes: 2 additions & 2 deletions cli/commands/automation/automation.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
22 changes: 11 additions & 11 deletions cli/commands/delete/delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -43,21 +47,17 @@ 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;
}
}
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;
Expand Down
61 changes: 61 additions & 0 deletions cli/commands/details/details.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#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"

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;
}

if(token_info->automation_features & TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END) {
TOTP_CLI_PRINTF(
"| %-20s | %-28.28s |\r\n", "Automation features", "Type <Enter> key at the end");
}
}

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");
}
Loading

0 comments on commit fd60525

Please sign in to comment.