Merge branch 'ul-dev' into xfw-dev
BIN
applications/external/brainfuck/icons/DolphinCommon_56x48.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
applications/external/brainfuck/icons/Text_10x10.png
vendored
Normal file
|
After Width: | Height: | Size: 158 B |
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
uint8_t counter = 0;
|
uint8_t counter = 0;
|
||||||
|
|
||||||
uint8_t id_list_ds1990[25][8] = {
|
uint8_t id_list_ds1990[18][8] = {
|
||||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, //– код универсального ключа, для Vizit
|
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, //– код универсального ключа, для Vizit
|
||||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
|
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
|
||||||
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
|
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
|
||||||
@@ -19,16 +19,9 @@ uint8_t id_list_ds1990[25][8] = {
|
|||||||
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
|
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
|
||||||
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
|
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // Only FF
|
||||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
{0x01, 0x78, 0x00, 0x48, 0xFD, 0xFF, 0xFF, 0xD1}, // StarNew Uni5
|
||||||
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0xE6}, // Eltis Uni
|
||||||
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
|
||||||
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
|
||||||
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
|
||||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
|
||||||
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
|
||||||
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
|
||||||
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t id_list_metakom[17][4] = {
|
uint8_t id_list_metakom[17][4] = {
|
||||||
@@ -51,7 +44,7 @@ uint8_t id_list_metakom[17][4] = {
|
|||||||
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
|
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t id_list_cyfral[14][2] = {
|
uint8_t id_list_cyfral[16][2] = {
|
||||||
{0x00, 0x00}, // Null bytes
|
{0x00, 0x00}, // Null bytes
|
||||||
{0xFF, 0xFF}, // Only FF
|
{0xFF, 0xFF}, // Only FF
|
||||||
{0x11, 0x11}, // Only 11
|
{0x11, 0x11}, // Only 11
|
||||||
@@ -66,6 +59,8 @@ uint8_t id_list_cyfral[14][2] = {
|
|||||||
{0x12, 0x34}, // Incremental UID
|
{0x12, 0x34}, // Incremental UID
|
||||||
{0x56, 0x34}, // Decremental UID
|
{0x56, 0x34}, // Decremental UID
|
||||||
{0xCA, 0xCA}, // ??
|
{0xCA, 0xCA}, // ??
|
||||||
|
{0x8E, 0xC9}, // Elevator code
|
||||||
|
{0x6A, 0x50}, // VERY fresh code from smartkey
|
||||||
};
|
};
|
||||||
|
|
||||||
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) {
|
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) {
|
||||||
@@ -130,7 +125,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) {
|
|||||||
context->payload[6] = id_list_ds1990[context->attack_step][6];
|
context->payload[6] = id_list_ds1990[context->attack_step][6];
|
||||||
context->payload[7] = id_list_ds1990[context->attack_step][7];
|
context->payload[7] = id_list_ds1990[context->attack_step][7];
|
||||||
|
|
||||||
if(context->attack_step == 24) {
|
if(context->attack_step == 17) {
|
||||||
context->attack_step = 0;
|
context->attack_step = 0;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
context->is_attacking = false;
|
context->is_attacking = false;
|
||||||
@@ -160,7 +155,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) {
|
|||||||
context->payload[0] = id_list_cyfral[context->attack_step][0];
|
context->payload[0] = id_list_cyfral[context->attack_step][0];
|
||||||
context->payload[1] = id_list_cyfral[context->attack_step][1];
|
context->payload[1] = id_list_cyfral[context->attack_step][1];
|
||||||
|
|
||||||
if(context->attack_step == 13) {
|
if(context->attack_step == 15) {
|
||||||
context->attack_step = 0;
|
context->attack_step = 0;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
context->is_attacking = false;
|
context->is_attacking = false;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
|
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
|
||||||
memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
|
memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
|
||||||
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
||||||
furi_string_cat_printf(csn_str, "%02X ", csn[i]);
|
furi_string_cat_printf(csn_str, "%02X", csn[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN);
|
bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN);
|
||||||
|
|||||||
1
applications/external/totp/application.fam
vendored
@@ -20,7 +20,6 @@ App(
|
|||||||
Lib(
|
Lib(
|
||||||
name="base64",
|
name="base64",
|
||||||
),
|
),
|
||||||
Lib(name="linked_list"),
|
|
||||||
Lib(
|
Lib(
|
||||||
name="timezone_utils",
|
name="timezone_utils",
|
||||||
),
|
),
|
||||||
|
|||||||
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) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
|
||||||
totp_cli_command_automation_handle(plugin_state, args, cli);
|
totp_cli_command_automation_handle(plugin_state, args, cli);
|
||||||
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
|
||||||
totp_cli_command_reset_handle(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) {
|
} else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
|
||||||
totp_cli_command_update_handle(plugin_state, args, cli);
|
totp_cli_command_update_handle(plugin_state, args, cli);
|
||||||
} else if(
|
} else if(
|
||||||
|
|||||||
42
applications/external/totp/cli/cli_helpers.c
vendored
@@ -3,6 +3,11 @@
|
|||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include "../types/plugin_event.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) {
|
bool totp_cli_ensure_authenticated(const PluginState* plugin_state, Cli* cli) {
|
||||||
if(plugin_state->current_scene == TotpSceneAuthentication) {
|
if(plugin_state->current_scene == TotpSceneAuthentication) {
|
||||||
TOTP_CLI_PRINTF("Pleases enter PIN on your flipper device\r\n");
|
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);
|
furi_delay_ms(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOTP_CLI_DELETE_LAST_LINE();
|
totp_cli_delete_last_line();
|
||||||
|
|
||||||
if(plugin_state->current_scene == TotpSceneAuthentication || //-V560
|
if(plugin_state->current_scene == TotpSceneAuthentication || //-V560
|
||||||
plugin_state->current_scene == TotpSceneNone) { //-V560
|
plugin_state->current_scene == TotpSceneNone) { //-V560
|
||||||
|
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||||
return false;
|
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) {
|
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
|
||||||
size_t out_str_size = furi_string_size(out_str);
|
size_t out_str_size = furi_string_size(out_str);
|
||||||
if(out_str_size > 0) {
|
if(out_str_size > 0) {
|
||||||
TOTP_CLI_DELETE_LAST_CHAR();
|
totp_cli_delete_last_char();
|
||||||
furi_string_left(out_str, out_str_size - 1);
|
furi_string_left(out_str, out_str_size - 1);
|
||||||
}
|
}
|
||||||
} else if(c == CliSymbolAsciiCR) {
|
} else if(c == CliSymbolAsciiCR) {
|
||||||
@@ -83,3 +89,35 @@ void furi_string_secure_free(FuriString* str) {
|
|||||||
|
|
||||||
furi_string_free(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
@@ -14,6 +14,11 @@
|
|||||||
#define DOCOPT_OPTIONS "[options]"
|
#define DOCOPT_OPTIONS "[options]"
|
||||||
#define DOCOPT_DEFAULT(val) "[default: " val "]"
|
#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(format, ...) printf(format, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define TOTP_CLI_PRINTF_COLORFUL(color, format, ...) \
|
#define TOTP_CLI_PRINTF_COLORFUL(color, format, ...) \
|
||||||
@@ -22,11 +27,6 @@
|
|||||||
printf("\e[0m"); \
|
printf("\e[0m"); \
|
||||||
fflush(stdout)
|
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, ...) \
|
#define TOTP_CLI_PRINTF_ERROR(format, ...) \
|
||||||
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_ERROR, format, ##__VA_ARGS__)
|
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_ERROR, format, ##__VA_ARGS__)
|
||||||
#define TOTP_CLI_PRINTF_WARNING(format, ...) \
|
#define TOTP_CLI_PRINTF_WARNING(format, ...) \
|
||||||
@@ -36,24 +36,12 @@
|
|||||||
#define TOTP_CLI_PRINTF_INFO(format, ...) \
|
#define TOTP_CLI_PRINTF_INFO(format, ...) \
|
||||||
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_INFO, format, ##__VA_ARGS__)
|
TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_INFO, format, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define TOTP_CLI_DELETE_LAST_LINE() \
|
#define TOTP_CLI_LOCK_UI(plugin_state) \
|
||||||
TOTP_CLI_PRINTF("\033[A\33[2K\r"); \
|
Scene __previous_scene = plugin_state->current_scene; \
|
||||||
fflush(stdout)
|
totp_scene_director_activate_scene(plugin_state, TotpSceneStandby)
|
||||||
|
|
||||||
#define TOTP_CLI_DELETE_CURRENT_LINE() \
|
#define TOTP_CLI_UNLOCK_UI(plugin_state) \
|
||||||
TOTP_CLI_PRINTF("\33[2K\r"); \
|
totp_scene_director_activate_scene(plugin_state, __previous_scene)
|
||||||
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")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether user is authenticated and entered correct PIN.
|
* @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
|
* @param str instance to free
|
||||||
*/
|
*/
|
||||||
void furi_string_secure_free(FuriString* str);
|
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
@@ -1,7 +1,6 @@
|
|||||||
#include "add.h"
|
#include "add.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../../services/convert/convert.h"
|
#include "../../../services/convert/convert.h"
|
||||||
@@ -9,6 +8,77 @@
|
|||||||
#include "../../../ui/scene_director.h"
|
#include "../../../ui/scene_director.h"
|
||||||
#include "../../common_command_arguments.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() {
|
void totp_cli_command_add_docopt_commands() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD ", " TOTP_CLI_COMMAND_ADD_ALT
|
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD ", " TOTP_CLI_COMMAND_ADD_ALT
|
||||||
", " TOTP_CLI_COMMAND_ADD_ALT2 " Add new token\r\n");
|
", " 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) {
|
void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||||
FuriString* temp_str = furi_string_alloc();
|
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t temp_cstr_len = furi_string_size(temp_str);
|
TokenInfoIteratorContext* iterator_context =
|
||||||
token_info->name = malloc(temp_cstr_len + 1);
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
furi_check(token_info->name != NULL);
|
|
||||||
strlcpy(token_info->name, furi_string_get_cstr(temp_str), temp_cstr_len + 1);
|
|
||||||
|
|
||||||
// Read optional arguments
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!parsed) {
|
struct TotpAddContext add_context = {.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
TotpIteratorUpdateTokenResult add_result =
|
||||||
furi_string_free(temp_str);
|
totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
|
||||||
token_info_free(token_info);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading token secret
|
if(add_result == TotpIteratorUpdateTokenResultSuccess) {
|
||||||
furi_string_reset(temp_str);
|
TOTP_CLI_PRINTF_SUCCESS(
|
||||||
TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n");
|
"Token \"%s\" has been successfully added\r\n",
|
||||||
if(!totp_cli_read_line(cli, temp_str, mask_user_input) ||
|
furi_string_get_cstr(
|
||||||
!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
totp_token_info_iterator_get_current_token(iterator_context)->name));
|
||||||
TOTP_CLI_DELETE_LAST_LINE();
|
} else if(add_result == TotpIteratorUpdateTokenResultCancelled) {
|
||||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||||
furi_string_secure_free(temp_str);
|
} else if(add_result == TotpIteratorUpdateTokenResultInvalidArguments) {
|
||||||
token_info_free(token_info);
|
totp_cli_print_invalid_arguments();
|
||||||
return;
|
} else if(add_result == TotpIteratorUpdateTokenResultInvalidSecret) {
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n");
|
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_CLI_UNLOCK_UI(plugin_state);
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ void totp_cli_command_automation_docopt_arguments() {
|
|||||||
"\r\n");
|
"\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
|
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||||
bool has_previous_method = false;
|
bool has_previous_method = false;
|
||||||
#endif
|
#endif
|
||||||
@@ -88,26 +88,20 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
if(!args_valid) {
|
if(!args_valid) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(new_method_provided) {
|
if(new_method_provided) {
|
||||||
Scene previous_scene = TotpSceneNone;
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin_state->automation_method = new_method;
|
plugin_state->automation_method = new_method;
|
||||||
if(totp_config_file_update_automation_method(new_method) ==
|
if(totp_config_file_update_automation_method(plugin_state)) {
|
||||||
TotpConfigFileUpdateSuccess) {
|
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
|
TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
|
||||||
totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
||||||
cli_nl();
|
cli_nl();
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
totp_cli_print_error_updating_config_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||||
@@ -118,9 +112,7 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(previous_scene != TotpSceneNone) {
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("Current automation method is ");
|
TOTP_CLI_PRINTF_INFO("Current automation method is ");
|
||||||
totp_cli_command_automation_print_method(
|
totp_cli_command_automation_print_method(
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
#include "../../../ui/scene_director.h"
|
#include "../../../ui/scene_director.h"
|
||||||
@@ -37,10 +36,13 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TokenInfoIteratorContext* iterator_context =
|
||||||
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
|
|
||||||
int token_number;
|
int token_number;
|
||||||
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||||
token_number > plugin_state->tokens_count) {
|
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,23 +53,27 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
|||||||
confirm_needed = false;
|
confirm_needed = false;
|
||||||
} else {
|
} else {
|
||||||
totp_cli_printf_unknown_argument(temp_str);
|
totp_cli_printf_unknown_argument(temp_str);
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
furi_string_free(temp_str);
|
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;
|
bool confirmed = !confirm_needed;
|
||||||
if(confirm_needed) {
|
if(confirm_needed) {
|
||||||
TOTP_CLI_PRINTF_WARNING("WARNING!\r\n");
|
TOTP_CLI_PRINTF_WARNING("WARNING!\r\n");
|
||||||
TOTP_CLI_PRINTF_WARNING(
|
TOTP_CLI_PRINTF_WARNING(
|
||||||
"TOKEN \"%s\" WILL BE PERMANENTLY DELETED WITHOUT ABILITY TO RECOVER IT.\r\n",
|
"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");
|
TOTP_CLI_PRINTF_WARNING("Confirm? [y/n]\r\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
char user_pick;
|
char user_pick;
|
||||||
@@ -80,32 +86,21 @@ void totp_cli_command_delete_handle(PluginState* plugin_state, FuriString* args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(confirmed) {
|
if(confirmed) {
|
||||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
totp_cli_print_processing();
|
||||||
return;
|
if(totp_token_info_iterator_remove_current_token_info(iterator_context)) {
|
||||||
}
|
totp_cli_delete_last_line();
|
||||||
|
|
||||||
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_PRINTF_SUCCESS(
|
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 {
|
} else {
|
||||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
totp_cli_delete_last_line();
|
||||||
}
|
totp_cli_print_error_updating_config_file();
|
||||||
|
totp_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||||
token_info_free(token_info);
|
|
||||||
|
|
||||||
if(activate_generate_token_scene) {
|
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("User has not confirmed\r\n");
|
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 "details.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../services/config/constants.h"
|
#include "../../../services/config/constants.h"
|
||||||
|
#include "../../../services/config/config.h"
|
||||||
|
#include "../../../ui/scene_director.h"
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
#include "../../common_command_arguments.h"
|
#include "../../common_command_arguments.h"
|
||||||
|
|
||||||
@@ -17,21 +18,21 @@
|
|||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
static void print_automation_features(const TokenInfo* token_info) {
|
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");
|
TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", "Automation features", "None");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool header_printed = false;
|
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);
|
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);
|
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);
|
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;
|
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 ||
|
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||||
token_number > plugin_state->tokens_count) {
|
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
return;
|
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("+----------------------+------------------------------+\r\n");
|
||||||
TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value");
|
TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value");
|
||||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
||||||
TOTP_CLI_PRINTF("| %-20s | %-28d |\r\n", "Index", token_number);
|
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(
|
||||||
TOTP_CLI_PRINTF(
|
"| %-20s | %-28.28s |\r\n", "Name", furi_string_get_cstr(token_info->name));
|
||||||
"| %-20s | %-28s |\r\n", "Hashing algorithm", token_info_get_algo_as_cstr(token_info));
|
TOTP_CLI_PRINTF(
|
||||||
TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", "Number of digits", token_info->digits);
|
"| %-20s | %-28s |\r\n", "Hashing algorithm", token_info_get_algo_as_cstr(token_info));
|
||||||
TOTP_CLI_PRINTF(
|
TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", "Number of digits", token_info->digits);
|
||||||
"| %-20s | %" PRIu8 " sec.%-21s |\r\n", "Token lifetime", token_info->duration, " ");
|
TOTP_CLI_PRINTF(
|
||||||
print_automation_features(token_info);
|
"| %-20s | %" PRIu8 " sec.%-21s |\r\n", "Token lifetime", token_info->duration, " ");
|
||||||
TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n");
|
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 "list.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../services/config/constants.h"
|
#include "../../../services/config/constants.h"
|
||||||
|
#include "../../../services/config/config.h"
|
||||||
|
#include "../../../ui/scene_director.h"
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
|
|
||||||
void totp_cli_command_list_docopt_commands() {
|
void totp_cli_command_list_docopt_commands() {
|
||||||
@@ -20,25 +21,36 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
|
|||||||
return;
|
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");
|
TOTP_CLI_PRINTF("There are no tokens");
|
||||||
return;
|
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("+-----+---------------------------+--------+----+-----+\r\n");
|
||||||
TOTP_CLI_PRINTF("| %-3s | %-25s | %-6s | %-s | %-s |\r\n", "#", "Name", "Algo", "Ln", "Dur");
|
TOTP_CLI_PRINTF("| %-3s | %-25s | %-6s | %-s | %-s |\r\n", "#", "Name", "Algo", "Ln", "Dur");
|
||||||
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
||||||
uint16_t index = 1;
|
for(size_t i = 0; i < total_count; i++) {
|
||||||
TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
|
totp_token_info_iterator_go_to(iterator_context, i);
|
||||||
TokenInfo* token_info = (TokenInfo*)node->data;
|
const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context);
|
||||||
TOTP_CLI_PRINTF(
|
TOTP_CLI_PRINTF(
|
||||||
"| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n",
|
"| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n",
|
||||||
index,
|
i + 1,
|
||||||
token_info->name,
|
furi_string_get_cstr(token_info->name),
|
||||||
token_info_get_algo_as_cstr(token_info),
|
token_info_get_algo_as_cstr(token_info),
|
||||||
token_info->digits,
|
token_info->digits,
|
||||||
token_info->duration);
|
token_info->duration);
|
||||||
index++;
|
}
|
||||||
});
|
|
||||||
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
|
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 <stdlib.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
@@ -33,42 +32,52 @@ void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, C
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int token_index;
|
int token_number;
|
||||||
if(!args_read_int_and_trim(args, &token_index) || token_index < 1 ||
|
TokenInfoIteratorContext* iterator_context =
|
||||||
token_index > plugin_state->tokens_count) {
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
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;
|
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 ||
|
if(!args_read_int_and_trim(args, &new_token_number) || new_token_number < 1 ||
|
||||||
new_token_index > plugin_state->tokens_count) {
|
(size_t)new_token_number > total_count) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool activate_generate_token_scene = false;
|
if(token_number == new_token_number) {
|
||||||
if(plugin_state->current_scene != TotpSceneAuthentication) {
|
TOTP_CLI_PRINTF_ERROR("New token number matches current token number\r\n");
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
return;
|
||||||
activate_generate_token_scene = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenInfo* token_info = NULL;
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
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(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(
|
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 {
|
} 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_token_info_iterator_go_to(iterator_context, original_token_index);
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
|
||||||
}
|
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");
|
", " 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;
|
bool has_previous_method = false;
|
||||||
if(method & NotificationMethodSound) {
|
if(method & NotificationMethodSound) {
|
||||||
TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "\"");
|
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 {
|
do {
|
||||||
if(!args_valid) {
|
if(!args_valid) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(new_method_provided) {
|
if(new_method_provided) {
|
||||||
Scene previous_scene = TotpSceneNone;
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin_state->notification_method = new_method;
|
plugin_state->notification_method = new_method;
|
||||||
if(totp_config_file_update_notification_method(new_method) ==
|
if(totp_config_file_update_notification_method(plugin_state)) {
|
||||||
TotpConfigFileUpdateSuccess) {
|
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Notification method is set to ");
|
TOTP_CLI_PRINTF_SUCCESS("Notification method is set to ");
|
||||||
totp_cli_command_notification_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
totp_cli_command_notification_print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
|
||||||
cli_nl();
|
cli_nl();
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
totp_cli_print_error_updating_config_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(previous_scene != TotpSceneNone) {
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("Current notification method is ");
|
TOTP_CLI_PRINTF_INFO("Current notification method is ");
|
||||||
totp_cli_command_notification_print_method(
|
totp_cli_command_notification_print_method(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../types/user_pin_codes.h"
|
#include "../../../types/user_pin_codes.h"
|
||||||
#include "../../../services/config/config.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) {
|
} else if(c == CliSymbolAsciiETX) {
|
||||||
TOTP_CLI_DELETE_CURRENT_LINE();
|
totp_cli_delete_current_line();
|
||||||
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n");
|
||||||
return false;
|
return false;
|
||||||
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
|
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
|
||||||
if(*pin_length > 0) {
|
if(*pin_length > 0) {
|
||||||
*pin_length = *pin_length - 1;
|
*pin_length = *pin_length - 1;
|
||||||
pin[*pin_length] = 0;
|
pin[*pin_length] = 0;
|
||||||
TOTP_CLI_DELETE_LAST_CHAR();
|
totp_cli_delete_last_char();
|
||||||
}
|
}
|
||||||
} else if(c == CliSymbolAsciiCR) {
|
} else if(c == CliSymbolAsciiCR) {
|
||||||
cli_nl();
|
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;
|
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) {
|
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
|
||||||
do_remove = true;
|
do_remove = true;
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) {
|
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 {
|
do {
|
||||||
uint8_t old_iv[TOTP_IV_SIZE];
|
uint8_t old_iv[TOTP_IV_SIZE];
|
||||||
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
||||||
uint8_t new_pin[TOTP_IV_SIZE];
|
uint8_t new_pin[TOTP_IV_SIZE];
|
||||||
|
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
||||||
uint8_t new_pin_length = 0;
|
uint8_t new_pin_length = 0;
|
||||||
if(do_change) {
|
if(do_change) {
|
||||||
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length) ||
|
if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) {
|
||||||
!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
|
||||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||||
break;
|
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);
|
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) {
|
if(backup_path != NULL) {
|
||||||
TOTP_CLI_PRINTF_WARNING("Backup conf file %s has been created\r\n", backup_path);
|
TOTP_CLI_PRINTF_WARNING("Backup conf file %s has been created\r\n", backup_path);
|
||||||
TOTP_CLI_PRINTF_WARNING(
|
TOTP_CLI_PRINTF_WARNING(
|
||||||
@@ -134,61 +133,28 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
TOTP_CLI_PRINTF("Encrypting...\r\n");
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
|
||||||
load_generate_token_scene = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TOTP_CLI_PRINTF("Encrypting, please wait...\r\n");
|
bool update_result =
|
||||||
|
totp_config_file_update_encryption(plugin_state, new_pin, new_pin_length);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||||
|
|
||||||
TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
|
totp_cli_delete_last_line();
|
||||||
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();
|
if(update_result) {
|
||||||
|
|
||||||
if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) {
|
|
||||||
if(do_change) {
|
if(do_change) {
|
||||||
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully changed\r\n");
|
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully changed\r\n");
|
||||||
} else if(do_remove) {
|
} else if(do_remove) {
|
||||||
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully removed\r\n");
|
TOTP_CLI_PRINTF_SUCCESS("PIN has been successfully removed\r\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
totp_cli_print_error_updating_config_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
if(load_generate_token_scene) {
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <furi/core/string.h>
|
#include <furi/core/string.h>
|
||||||
#include "../../cli_helpers.h"
|
#include "../../cli_helpers.h"
|
||||||
|
#include "../../../ui/scene_director.h"
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
|
|
||||||
#define TOTP_CLI_RESET_CONFIRMATION_KEYWORD "YES"
|
#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");
|
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(
|
TOTP_CLI_PRINTF_WARNING(
|
||||||
"As a result of reset all the settings and tokens will be permanently lost.\r\n");
|
"As a result of reset all the settings and tokens will be permanently lost.\r\n");
|
||||||
TOTP_CLI_PRINTF_WARNING("Do you really want to reset application?\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_cmpi_str(temp_str, TOTP_CLI_RESET_CONFIRMATION_KEYWORD) == 0;
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
if(is_confirmed) {
|
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("Application has been successfully reset to default.\r\n");
|
||||||
TOTP_CLI_PRINTF_SUCCESS("Now application will be closed to apply all the changes.\r\n");
|
TOTP_CLI_PRINTF_SUCCESS("Now application will be closed to apply all the changes.\r\n");
|
||||||
totp_cli_force_close_app(event_queue);
|
totp_cli_force_close_app(event_queue);
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
|
TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
|
||||||
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#define TOTP_CLI_COMMAND_RESET "reset"
|
#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_commands();
|
||||||
void totp_cli_command_reset_docopt_usage();
|
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;
|
char* strtof_endptr;
|
||||||
float tz = strtof(furi_string_get_cstr(temp_str), &strtof_endptr);
|
float tz = strtof(furi_string_get_cstr(temp_str), &strtof_endptr);
|
||||||
if(*strtof_endptr == 0 && tz >= -12.75f && tz <= 12.75f) {
|
if(*strtof_endptr == 0 && tz >= -12.75f && tz <= 12.75f) {
|
||||||
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
plugin_state->timezone_offset = tz;
|
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);
|
TOTP_CLI_PRINTF_SUCCESS("Timezone is set to %f\r\n", (double)tz);
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
|
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_UNLOCK_UI(plugin_state);
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_ERROR("Invalid timezone offset\r\n");
|
TOTP_CLI_PRINTF_ERROR("Invalid timezone offset\r\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "update.h"
|
#include "update.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../../services/convert/convert.h"
|
#include "../../../services/convert/convert.h"
|
||||||
@@ -11,6 +10,103 @@
|
|||||||
|
|
||||||
#define TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX "-s"
|
#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() {
|
void totp_cli_command_update_docopt_commands() {
|
||||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_UPDATE " Update existing token\r\n");
|
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");
|
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) {
|
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)) {
|
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TokenInfoIteratorContext* iterator_context =
|
||||||
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
|
|
||||||
int token_number;
|
int token_number;
|
||||||
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
if(!args_read_int_and_trim(args, &token_number) || token_number <= 0 ||
|
||||||
token_number > plugin_state->tokens_count) {
|
(size_t)token_number > totp_token_info_iterator_get_total_count(iterator_context)) {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
totp_cli_print_invalid_arguments();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode* list_item = list_element_at(plugin_state->tokens_list, token_number - 1);
|
TOTP_CLI_LOCK_UI(plugin_state);
|
||||||
TokenInfo* existing_token_info = list_item->data;
|
|
||||||
TokenInfo* token_info = token_info_clone(existing_token_info);
|
|
||||||
|
|
||||||
// Read optional arguments
|
size_t previous_index = totp_token_info_iterator_get_current_token_index(iterator_context);
|
||||||
bool mask_user_input = true;
|
totp_token_info_iterator_go_to(iterator_context, token_number - 1);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!parsed) {
|
struct TotpUpdateContext update_context = {
|
||||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
.args = args, .cli = cli, .iv = &plugin_state->iv[0]};
|
||||||
furi_string_free(temp_str);
|
TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
|
||||||
token_info_free(token_info);
|
iterator_context, &update_token_handler, &update_context);
|
||||||
return;
|
|
||||||
}
|
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;
|
totp_token_info_iterator_go_to(iterator_context, previous_index);
|
||||||
if(update_token_secret) {
|
TOTP_CLI_UNLOCK_UI(plugin_state);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "common_command_arguments.h"
|
#include "common_command_arguments.h"
|
||||||
#include <lib/toolbox/args.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);
|
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));
|
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);
|
totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX);
|
||||||
} else {
|
} else {
|
||||||
if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE32_NAME) == 0) {
|
if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE32_NAME) == 0) {
|
||||||
*secret_encoding = PLAIN_TOKEN_ENCODING_BASE32;
|
*secret_encoding = PlainTokenSecretEncodingBase32;
|
||||||
*parsed = true;
|
*parsed = true;
|
||||||
} else if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE64_NAME) == 0) {
|
} else if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE64_NAME) == 0) {
|
||||||
*secret_encoding = PLAIN_TOKEN_ENCODING_BASE64;
|
*secret_encoding = PlainTokenSecretEncodingBase64;
|
||||||
*parsed = true;
|
*parsed = true;
|
||||||
} else {
|
} else {
|
||||||
TOTP_CLI_PRINTF_ERROR(
|
TOTP_CLI_PRINTF_ERROR(
|
||||||
|
|||||||
@@ -19,23 +19,29 @@
|
|||||||
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding"
|
#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding"
|
||||||
|
|
||||||
void totp_cli_printf_unknown_argument(const FuriString* arg);
|
void totp_cli_printf_unknown_argument(const FuriString* arg);
|
||||||
|
|
||||||
void totp_cli_printf_missed_argument_value(char* 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_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed);
|
||||||
|
|
||||||
bool totp_cli_try_read_digits(
|
bool totp_cli_try_read_digits(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
const FuriString* arg,
|
const FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
bool totp_cli_try_read_duration(
|
bool totp_cli_try_read_duration(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
const FuriString* arg,
|
const FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
bool totp_cli_try_read_automation_features(
|
bool totp_cli_try_read_automation_features(
|
||||||
TokenInfo* token_info,
|
TokenInfo* token_info,
|
||||||
FuriString* arg,
|
FuriString* arg,
|
||||||
FuriString* args,
|
FuriString* args,
|
||||||
bool* parsed);
|
bool* parsed);
|
||||||
|
|
||||||
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag);
|
bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag);
|
||||||
|
|
||||||
bool totp_cli_try_read_plain_token_secret_encoding(
|
bool totp_cli_try_read_plain_token_secret_encoding(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Base64 encoding/decoding (RFC1341)
|
* Base64 encoding/decoding (RFC1341)
|
||||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
* 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
|
* 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
|
* 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(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
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef uint8_t TotpRollValueOverflowBehavior;
|
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);
|
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.
|
* When value reaches constraint value \p overflow_behavior defines what to do next.
|
||||||
* @param[in,out] value value to roll
|
* @param[in,out] value value to roll
|
||||||
* @param step step to be used to change value
|
* @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 max maximum possible value
|
||||||
* @param overflow_behavior defines what to do when value reaches constraint 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);
|
||||||
809
applications/external/totp/services/config/config.c
vendored
127
applications/external/totp/services/config/config.h
vendored
@@ -1,137 +1,90 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <flipper_format/flipper_format.h>
|
|
||||||
#include "../../types/plugin_state.h"
|
#include "../../types/plugin_state.h"
|
||||||
#include "../../types/token_info.h"
|
#include "../../types/token_info.h"
|
||||||
|
#include "config_file_context.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "token_info_iterator.h"
|
||||||
|
|
||||||
typedef uint8_t TokenLoadingResult;
|
|
||||||
typedef uint8_t TotpConfigFileOpenResult;
|
typedef uint8_t TotpConfigFileOpenResult;
|
||||||
typedef uint8_t TotpConfigFileUpdateResult;
|
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
|
* @brief Tries to take a config file backup
|
||||||
|
* @param plugin_state application state
|
||||||
* @return backup path if backup successfully taken; \c NULL otherwise
|
* @return backup path if backup successfully taken; \c NULL otherwise
|
||||||
*/
|
*/
|
||||||
char* totp_config_file_backup();
|
char* totp_config_file_backup(const PluginState* plugin_state);
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loads basic information from an application config file into application state without loading all the tokens
|
* @brief Loads basic information from an application config file into application state without loading all the tokens
|
||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
* @return Config file open result
|
* @return Config file open result
|
||||||
*/
|
*/
|
||||||
TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_state);
|
bool totp_config_file_load(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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates timezone offset in an application config file
|
* @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
|
* @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
|
* @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
|
* @return Config file update result
|
||||||
*/
|
*/
|
||||||
TotpConfigFileUpdateResult
|
bool totp_config_file_update_notification_method(const PluginState* plugin_state);
|
||||||
totp_config_file_update_notification_method(NotificationMethod new_notification_method);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates automation method in an application config file
|
* @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
|
* @return Config file update result
|
||||||
*/
|
*/
|
||||||
TotpConfigFileUpdateResult
|
bool totp_config_file_update_automation_method(const PluginState* plugin_state);
|
||||||
totp_config_file_update_automation_method(AutomationMethod new_automation_method);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates application user settings
|
* @brief Updates application user settings
|
||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
* @return Config file update result
|
* @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
|
* @brief Updates crypto signatures information
|
||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
* @return Config file update result
|
* @return Config file update result
|
||||||
*/
|
*/
|
||||||
TotpConfigFileUpdateResult
|
bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
|
||||||
totp_config_file_update_crypto_signatures(const PluginState* plugin_state);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset all the settings to default
|
* @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
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct ConfigFileContext ConfigFileContext;
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#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_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_TIMEZONE "Timezone"
|
||||||
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "common_migration.h"
|
#include "common_migration.h"
|
||||||
#include "../constants.h"
|
#include "../constants.h"
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
|
#include <flipper_format/flipper_format_i.h>
|
||||||
|
|
||||||
bool totp_config_migrate_to_latest(
|
bool totp_config_migrate_to_latest(
|
||||||
FlipperFormat* fff_data_file,
|
FlipperFormat* fff_data_file,
|
||||||
@@ -57,18 +58,12 @@ bool totp_config_migrate_to_latest(
|
|||||||
|
|
||||||
flipper_format_rewind(fff_backup_data_file);
|
flipper_format_rewind(fff_backup_data_file);
|
||||||
|
|
||||||
FuriString* comment_str = furi_string_alloc();
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
if(!flipper_format_read_string(
|
if(!flipper_format_read_string(
|
||||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
||||||
break;
|
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_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
|
||||||
|
|
||||||
flipper_format_read_string(
|
flipper_format_read_string(
|
||||||
@@ -78,15 +73,32 @@ bool totp_config_migrate_to_latest(
|
|||||||
if(current_version > 1) {
|
if(current_version > 1) {
|
||||||
flipper_format_read_string(
|
flipper_format_read_string(
|
||||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
|
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(
|
flipper_format_read_string(
|
||||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
|
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);
|
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
|
||||||
} else {
|
} else {
|
||||||
flipper_format_write_string_cstr(
|
const uint32_t default_algo = SHA1;
|
||||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_TOKEN_ALGO_SHA1_NAME);
|
flipper_format_write_uint32(
|
||||||
const uint32_t default_digits = TOTP_6_DIGITS;
|
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &default_algo, 1);
|
||||||
|
const uint32_t default_digits = TotpSixDigitsCount;
|
||||||
flipper_format_write_uint32(
|
flipper_format_write_uint32(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
|
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(
|
flipper_format_write_string(
|
||||||
fff_data_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, temp_str);
|
fff_data_file, TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES, temp_str);
|
||||||
} else {
|
} else {
|
||||||
const uint32_t default_automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
|
const uint32_t default_automation_features = TokenAutomationFeatureNone;
|
||||||
flipper_format_write_uint32(
|
flipper_format_write_uint32(
|
||||||
fff_data_file,
|
fff_data_file,
|
||||||
TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES,
|
TOTP_CONFIG_KEY_TOKEN_AUTOMATION_FEATURES,
|
||||||
&default_automation_features,
|
&default_automation_features,
|
||||||
1);
|
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;
|
result = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
#include <flipper_format/flipper_format.h>
|
#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(
|
bool totp_config_migrate_to_latest(
|
||||||
FlipperFormat* fff_data_file,
|
FlipperFormat* fff_data_file,
|
||||||
FlipperFormat* fff_backup_data_file);
|
FlipperFormat* fff_backup_data_file);
|
||||||
547
applications/external/totp/services/config/token_info_iterator.c
vendored
Normal file
@@ -0,0 +1,547 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) ||
|
||||||
|
!token_info_set_algo_from_int(tokenInfo, temp_data32)) {
|
||||||
|
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
@@ -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_crypto.h>
|
||||||
#include <furi_hal_random.h>
|
#include <furi_hal_random.h>
|
||||||
#include <furi_hal_version.h>
|
#include <furi_hal_version.h>
|
||||||
#include "../config/config.h"
|
|
||||||
#include "../../types/common.h"
|
#include "../../types/common.h"
|
||||||
#include "memset_s.h"
|
#include "memset_s.h"
|
||||||
|
|
||||||
@@ -62,9 +61,11 @@ uint8_t* totp_crypto_decrypt(
|
|||||||
return decrypted_data;
|
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) {
|
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);
|
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) {
|
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);
|
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
|
||||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
furi_check(plugin_state->crypto_verify_data != NULL);
|
||||||
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
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;
|
plugin_state->pin_set = pin != NULL && pin_length > 0;
|
||||||
|
|
||||||
result = totp_config_file_update_crypto_signatures(plugin_state) ==
|
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||||
TotpConfigFileUpdateSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -2,6 +2,26 @@
|
|||||||
|
|
||||||
#include "../../types/plugin_state.h"
|
#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)
|
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||||
* @param plain_data plain data to be encrypted
|
* @param plain_data plain data to be encrypted
|
||||||
@@ -35,9 +55,10 @@ uint8_t* totp_crypto_decrypt(
|
|||||||
* @param plugin_state application state
|
* @param plugin_state application state
|
||||||
* @param pin user's PIN
|
* @param pin user's PIN
|
||||||
* @param pin_length user's PIN length
|
* @param pin_length user's PIN length
|
||||||
* @return \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
|
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sha256.h"
|
|
||||||
#include "memxor.h"
|
#include "memxor.h"
|
||||||
|
|
||||||
#define IPAD 0x36
|
#define IPAD 0x36
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "hmac_sha256.h"
|
#include "hmac_sha256.h"
|
||||||
|
#include "sha256.h"
|
||||||
|
|
||||||
#define GL_HMAC_NAME 256
|
#define GL_HMAC_NAME 256
|
||||||
#define GL_HMAC_BLOCKSIZE 64
|
#define GL_HMAC_BLOCKSIZE 64
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define SWAP(n) (n)
|
#define SWAP(n) (n)
|
||||||
#else
|
#else
|
||||||
@@ -34,10 +36,6 @@
|
|||||||
#define SWAP(n) swap_uint32(n)
|
#define SWAP(n) swap_uint32(n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
|
||||||
static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
|
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
|
||||||
initialize it to the start constants of the SHA1 algorithm. This
|
initialize it to the start constants of the SHA1 algorithm. This
|
||||||
must be called before using hash in the call to sha1_hash. */
|
must be called before using hash in the call to sha1_hash. */
|
||||||
@@ -87,7 +85,7 @@ void* sha1_finish_ctx(struct sha1_ctx* ctx, void* resbuf) {
|
|||||||
ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
|
ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
|
||||||
ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3);
|
ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3);
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha1_process_block(ctx->buffer, size * 4, ctx);
|
sha1_process_block(ctx->buffer, size * 4, ctx);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define SWAP(n) (n)
|
#define SWAP(n) (n)
|
||||||
@@ -33,10 +34,6 @@
|
|||||||
#define SWAP(n) swap_uint32(n)
|
#define SWAP(n) swap_uint32(n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
64-byte boundary. */
|
|
||||||
static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
|
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
|
||||||
initializes it to the start constants of the SHA256 algorithm. This
|
initializes it to the start constants of the SHA256 algorithm. This
|
||||||
@@ -91,7 +88,7 @@ static void sha256_conclude_ctx(struct sha256_ctx* ctx) {
|
|||||||
set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
|
set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
|
||||||
set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3));
|
set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3));
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha256_process_block(ctx->buffer, size * 4, ctx);
|
sha256_process_block(ctx->buffer, size * 4, ctx);
|
||||||
|
|||||||
@@ -27,13 +27,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "byteswap.h"
|
#include "byteswap.h"
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#define SWAP(n) swap_uint64(n)
|
#define SWAP(n) swap_uint64(n)
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
128-byte boundary. */
|
|
||||||
static const unsigned char fillbuf[128] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
|
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
|
||||||
initializes it to the start constants of the SHA512 algorithm. This
|
initializes it to the start constants of the SHA512 algorithm. This
|
||||||
@@ -90,7 +87,7 @@ static void sha512_conclude_ctx(struct sha512_ctx* ctx) {
|
|||||||
SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61))));
|
SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61))));
|
||||||
set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3)));
|
set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3)));
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 8 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha512_process_block(ctx->buffer, size * 8, ctx);
|
sha512_process_block(ctx->buffer, size * 8, ctx);
|
||||||
|
|||||||
11
applications/external/totp/services/hmac/sha_pad_buffer.c
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void sha_pad_buffer(uint8_t* buffer, size_t size) {
|
||||||
|
if(size > 0) {
|
||||||
|
buffer[0] = 0x80;
|
||||||
|
if(size > 1) {
|
||||||
|
memset(&buffer[1], 0, size - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
applications/external/totp/services/hmac/sha_pad_buffer.h
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void sha_pad_buffer(uint8_t* buffer, size_t size);
|
||||||
43
applications/external/totp/totp_app.c
vendored
@@ -50,23 +50,39 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
|
|||||||
dialog_message_show(plugin_state->dialogs_app, message);
|
dialog_message_show(plugin_state->dialogs_app, message);
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
if(dialog_result == DialogMessageButtonRight) {
|
if(dialog_result == DialogMessageButtonRight) {
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||||
} else {
|
} 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);
|
totp_dialogs_config_loading_error(plugin_state);
|
||||||
return false;
|
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) {
|
} else if(plugin_state->pin_set) {
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication);
|
||||||
} else {
|
} 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);
|
totp_dialogs_config_loading_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(totp_crypto_verify_key(plugin_state)) {
|
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 {
|
} else {
|
||||||
FURI_LOG_E(
|
FURI_LOG_E(
|
||||||
LOGGING_TAG,
|
LOGGING_TAG,
|
||||||
@@ -95,7 +111,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
|||||||
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
||||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
memset(&plugin_state->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);
|
totp_dialogs_config_loading_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -118,15 +134,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
|
|||||||
furi_record_close(RECORD_NOTIFICATION);
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
|
||||||
ListNode* node = plugin_state->tokens_list;
|
totp_config_file_close(plugin_state);
|
||||||
ListNode* tmp;
|
|
||||||
while(node != NULL) {
|
|
||||||
tmp = node->next;
|
|
||||||
TokenInfo* tokenInfo = node->data;
|
|
||||||
token_info_free(tokenInfo);
|
|
||||||
free(node);
|
|
||||||
node = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(plugin_state->crypto_verify_data != NULL) {
|
if(plugin_state->crypto_verify_data != NULL) {
|
||||||
free(plugin_state->crypto_verify_data);
|
free(plugin_state->crypto_verify_data);
|
||||||
@@ -189,8 +197,9 @@ int32_t totp_app() {
|
|||||||
}
|
}
|
||||||
} else if(
|
} else if(
|
||||||
plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication &&
|
plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication &&
|
||||||
|
plugin_state->current_scene != TotpSceneStandby &&
|
||||||
furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
|
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);
|
view_port_update(view_port);
|
||||||
|
|||||||
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
@@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define LOGGING_TAG "TOTP APP"
|
extern const char* LOGGING_TAG;
|
||||||
|
|||||||
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
@@ -4,8 +4,8 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
#include "../features_config.h"
|
#include "../features_config.h"
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../ui/totp_scenes_enum.h"
|
#include "../ui/totp_scenes_enum.h"
|
||||||
|
#include "../services/config/config_file_context.h"
|
||||||
#include "notification_method.h"
|
#include "notification_method.h"
|
||||||
#include "automation_method.h"
|
#include "automation_method.h"
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||||
@@ -48,20 +48,7 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
float timezone_offset;
|
float timezone_offset;
|
||||||
|
|
||||||
/**
|
ConfigFileContext* config_file_context;
|
||||||
* @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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypted well-known string data
|
* @brief Encrypted well-known string data
|
||||||
|
|||||||
66
applications/external/totp/types/token_info.c
vendored
@@ -8,17 +8,15 @@
|
|||||||
TokenInfo* token_info_alloc() {
|
TokenInfo* token_info_alloc() {
|
||||||
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
|
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
|
||||||
furi_check(tokenInfo != NULL);
|
furi_check(tokenInfo != NULL);
|
||||||
tokenInfo->algo = SHA1;
|
tokenInfo->name = furi_string_alloc();
|
||||||
tokenInfo->digits = TOTP_6_DIGITS;
|
token_info_set_defaults(tokenInfo);
|
||||||
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
|
|
||||||
tokenInfo->automation_features = TOKEN_AUTOMATION_FEATURE_NONE;
|
|
||||||
return tokenInfo;
|
return tokenInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void token_info_free(TokenInfo* token_info) {
|
void token_info_free(TokenInfo* token_info) {
|
||||||
if(token_info == NULL) return;
|
if(token_info == NULL) return;
|
||||||
free(token_info->name);
|
|
||||||
free(token_info->token);
|
free(token_info->token);
|
||||||
|
furi_string_free(token_info->name);
|
||||||
free(token_info);
|
free(token_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,13 +30,13 @@ bool token_info_set_secret(
|
|||||||
uint8_t* plain_secret;
|
uint8_t* plain_secret;
|
||||||
size_t plain_secret_length;
|
size_t plain_secret_length;
|
||||||
size_t plain_secret_size;
|
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_size = token_secret_length;
|
||||||
plain_secret = malloc(plain_secret_size);
|
plain_secret = malloc(plain_secret_size);
|
||||||
furi_check(plain_secret != NULL);
|
furi_check(plain_secret != NULL);
|
||||||
plain_secret_length =
|
plain_secret_length =
|
||||||
base32_decode((const uint8_t*)plain_token_secret, plain_secret, plain_secret_size);
|
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_length = 0;
|
||||||
plain_secret = base64_decode(
|
plain_secret = base64_decode(
|
||||||
(const uint8_t*)plain_token_secret,
|
(const uint8_t*)plain_token_secret,
|
||||||
@@ -52,6 +50,10 @@ bool token_info_set_secret(
|
|||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
if(plain_secret_length > 0) {
|
if(plain_secret_length > 0) {
|
||||||
|
if(token_info->token != NULL) {
|
||||||
|
free(token_info->token);
|
||||||
|
}
|
||||||
|
|
||||||
token_info->token =
|
token_info->token =
|
||||||
totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
|
totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
|
||||||
result = true;
|
result = true;
|
||||||
@@ -67,13 +69,13 @@ bool token_info_set_secret(
|
|||||||
bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
|
bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
|
||||||
switch(digits) {
|
switch(digits) {
|
||||||
case 5:
|
case 5:
|
||||||
token_info->digits = TOTP_5_DIGITS;
|
token_info->digits = TotpFiveDigitsCount;
|
||||||
return true;
|
return true;
|
||||||
case 6:
|
case 6:
|
||||||
token_info->digits = TOTP_6_DIGITS;
|
token_info->digits = TotpSixDigitsCount;
|
||||||
return true;
|
return true;
|
||||||
case 8:
|
case 8:
|
||||||
token_info->digits = TOTP_8_DIGITS;
|
token_info->digits = TotpEightDigitsCount;
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -115,6 +117,27 @@ bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code) {
|
||||||
|
switch(algo_code) {
|
||||||
|
case SHA1:
|
||||||
|
token_info->algo = SHA1;
|
||||||
|
break;
|
||||||
|
case SHA256:
|
||||||
|
token_info->algo = SHA256;
|
||||||
|
break;
|
||||||
|
case SHA512:
|
||||||
|
token_info->algo = SHA512;
|
||||||
|
break;
|
||||||
|
case STEAM:
|
||||||
|
token_info->algo = STEAM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
|
char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
|
||||||
switch(token_info->algo) {
|
switch(token_info->algo) {
|
||||||
case SHA1:
|
case SHA1:
|
||||||
@@ -134,22 +157,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) {
|
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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME) == 0) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME) == 0) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_string_cmpi_str(str, TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME) == 0) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,10 +187,17 @@ TokenInfo* token_info_clone(const TokenInfo* src) {
|
|||||||
furi_check(clone->token != NULL);
|
furi_check(clone->token != NULL);
|
||||||
memcpy(clone->token, src->token, src->token_length);
|
memcpy(clone->token, src->token, src->token_length);
|
||||||
|
|
||||||
int name_length = strnlen(src->name, TOTP_TOKEN_MAX_LENGTH);
|
clone->name = furi_string_alloc();
|
||||||
clone->name = malloc(name_length + 1);
|
furi_string_set(clone->name, src->name);
|
||||||
furi_check(clone->name != NULL);
|
|
||||||
strlcpy(clone->name, src->name, name_length + 1);
|
|
||||||
|
|
||||||
return clone;
|
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);
|
||||||
|
}
|
||||||
52
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_TAB_AT_THE_END_NAME "tab"
|
||||||
#define TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME "slower"
|
#define TOTP_TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER_NAME "slower"
|
||||||
|
|
||||||
|
#define TOTP_TOKEN_DIGITS_MAX_COUNT (8)
|
||||||
|
|
||||||
typedef uint8_t TokenHashAlgo;
|
typedef uint8_t TokenHashAlgo;
|
||||||
typedef uint8_t TokenDigitsCount;
|
typedef uint8_t TokenDigitsCount;
|
||||||
typedef uint8_t TokenAutomationFeature;
|
typedef uint8_t TokenAutomationFeature;
|
||||||
@@ -32,22 +34,22 @@ enum TokenHashAlgos {
|
|||||||
/**
|
/**
|
||||||
* @brief SHA1 hashing algorithm
|
* @brief SHA1 hashing algorithm
|
||||||
*/
|
*/
|
||||||
SHA1,
|
SHA1 = 0,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SHA256 hashing algorithm
|
* @brief SHA256 hashing algorithm
|
||||||
*/
|
*/
|
||||||
SHA256,
|
SHA256 = 1,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SHA512 hashing algorithm
|
* @brief SHA512 hashing algorithm
|
||||||
*/
|
*/
|
||||||
SHA512,
|
SHA512 = 2,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Algorithm used by Steam (Valve)
|
* @brief Algorithm used by Steam (Valve)
|
||||||
*/
|
*/
|
||||||
STEAM
|
STEAM = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,19 +57,19 @@ enum TokenHashAlgos {
|
|||||||
*/
|
*/
|
||||||
enum TokenDigitsCounts {
|
enum TokenDigitsCounts {
|
||||||
/**
|
/**
|
||||||
* @brief 6 digits
|
* @brief 5 digits
|
||||||
*/
|
*/
|
||||||
TOTP_5_DIGITS = 5,
|
TotpFiveDigitsCount = 5,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 6 digits
|
* @brief 6 digits
|
||||||
*/
|
*/
|
||||||
TOTP_6_DIGITS = 6,
|
TotpSixDigitsCount = 6,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 8 digits
|
* @brief 8 digits
|
||||||
*/
|
*/
|
||||||
TOTP_8_DIGITS = 8
|
TotpEightDigitsCount = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,22 +79,22 @@ enum TokenAutomationFeatures {
|
|||||||
/**
|
/**
|
||||||
* @brief No features enabled
|
* @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
|
* @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
|
* @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
|
* @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
|
* @brief Base32 encoding
|
||||||
*/
|
*/
|
||||||
PLAIN_TOKEN_ENCODING_BASE32 = 0,
|
PlainTokenSecretEncodingBase32 = 0,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base64 encoding
|
* @brief Base64 encoding
|
||||||
*/
|
*/
|
||||||
PLAIN_TOKEN_ENCODING_BASE64 = 1
|
PlainTokenSecretEncodingBase64 = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT (8)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TOTP token information
|
* @brief TOTP token information
|
||||||
*/
|
*/
|
||||||
@@ -130,7 +130,7 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* @brief User-friendly token name
|
* @brief User-friendly token name
|
||||||
*/
|
*/
|
||||||
char* name;
|
FuriString* name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hashing algorithm
|
* @brief Hashing algorithm
|
||||||
@@ -168,7 +168,7 @@ void token_info_free(TokenInfo* token_info);
|
|||||||
/**
|
/**
|
||||||
* @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo
|
* @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo
|
||||||
* @param token_info instance where secret should be updated
|
* @param token_info instance where secret should be updated
|
||||||
* @param base32_token_secret plain token secret in Base32 format
|
* @param plain_token_secret plain token secret
|
||||||
* @param token_secret_length plain token secret length
|
* @param token_secret_length plain token secret length
|
||||||
* @param plain_token_secret_encoding plain token secret encoding
|
* @param plain_token_secret_encoding plain token secret encoding
|
||||||
* @param iv initialization vecor (IV) to be used for encryption
|
* @param iv initialization vecor (IV) to be used for encryption
|
||||||
@@ -201,10 +201,18 @@ bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration);
|
|||||||
* @brief Sets token hashing algorithm from \c str value
|
* @brief Sets token hashing algorithm from \c str value
|
||||||
* @param token_info instance whichs token hashing algorithm should be updated
|
* @param token_info instance whichs token hashing algorithm should be updated
|
||||||
* @param str desired token algorithm
|
* @param str desired token algorithm
|
||||||
* @return \c true if token hahsing algorithm has been updated; \c false otherwise
|
* @return \c true if token hashing algorithm has been updated; \c false otherwise
|
||||||
*/
|
*/
|
||||||
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str);
|
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets token hashing algorithm from \c algo_code code
|
||||||
|
* @param token_info instance whichs token hashing algorithm should be updated
|
||||||
|
* @param algo_code desired token algorithm code
|
||||||
|
* @return \c true if token hashing algorithm has been updated; \c false otherwise
|
||||||
|
*/
|
||||||
|
bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets token hahsing algorithm name as C-string
|
* @brief Gets token hahsing algorithm name as C-string
|
||||||
* @param token_info instance which token hahsing algorithm name should be returned
|
* @param token_info instance which token hahsing algorithm name should be returned
|
||||||
@@ -226,3 +234,9 @@ bool token_info_set_automation_feature_from_str(TokenInfo* token_info, const Fur
|
|||||||
* @return cloned instance
|
* @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
@@ -5,29 +5,28 @@
|
|||||||
#include "scenes/add_new_token/totp_scene_add_new_token.h"
|
#include "scenes/add_new_token/totp_scene_add_new_token.h"
|
||||||
#include "scenes/token_menu/totp_scene_token_menu.h"
|
#include "scenes/token_menu/totp_scene_token_menu.h"
|
||||||
#include "scenes/app_settings/totp_app_settings.h"
|
#include "scenes/app_settings/totp_app_settings.h"
|
||||||
|
#include "scenes/standby/standby.h"
|
||||||
|
|
||||||
void totp_scene_director_activate_scene(
|
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene) {
|
||||||
PluginState* const plugin_state,
|
|
||||||
Scene scene,
|
|
||||||
const void* context) {
|
|
||||||
totp_scene_director_deactivate_active_scene(plugin_state);
|
totp_scene_director_deactivate_active_scene(plugin_state);
|
||||||
switch(scene) {
|
switch(scene) {
|
||||||
case TotpSceneGenerateToken:
|
case TotpSceneGenerateToken:
|
||||||
totp_scene_generate_token_activate(plugin_state, context);
|
totp_scene_generate_token_activate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneAuthentication:
|
case TotpSceneAuthentication:
|
||||||
totp_scene_authenticate_activate(plugin_state);
|
totp_scene_authenticate_activate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneAddNewToken:
|
case TotpSceneAddNewToken:
|
||||||
totp_scene_add_new_token_activate(plugin_state, context);
|
totp_scene_add_new_token_activate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneTokenMenu:
|
case TotpSceneTokenMenu:
|
||||||
totp_scene_token_menu_activate(plugin_state, context);
|
totp_scene_token_menu_activate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneAppSettings:
|
case TotpSceneAppSettings:
|
||||||
totp_scene_app_settings_activate(plugin_state, context);
|
totp_scene_app_settings_activate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneNone:
|
case TotpSceneNone:
|
||||||
|
case TotpSceneStandby:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -56,6 +55,7 @@ void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state
|
|||||||
totp_scene_app_settings_deactivate(plugin_state);
|
totp_scene_app_settings_deactivate(plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneNone:
|
case TotpSceneNone:
|
||||||
|
case TotpSceneStandby:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -81,6 +81,9 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_
|
|||||||
break;
|
break;
|
||||||
case TotpSceneNone:
|
case TotpSceneNone:
|
||||||
break;
|
break;
|
||||||
|
case TotpSceneStandby:
|
||||||
|
totp_scene_standby_render(canvas);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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);
|
processing = totp_scene_app_settings_handle_event(event, plugin_state);
|
||||||
break;
|
break;
|
||||||
case TotpSceneNone:
|
case TotpSceneNone:
|
||||||
|
case TotpSceneStandby:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,10 +11,7 @@
|
|||||||
* @param scene scene to be activated
|
* @param scene scene to be activated
|
||||||
* @param context scene context to be passed to the scene activation method
|
* @param context scene context to be passed to the scene activation method
|
||||||
*/
|
*/
|
||||||
void totp_scene_director_activate_scene(
|
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene);
|
||||||
PluginState* const plugin_state,
|
|
||||||
Scene scene,
|
|
||||||
const void* context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deactivate current scene
|
* @brief Deactivate current scene
|
||||||
|
|||||||
@@ -4,17 +4,18 @@
|
|||||||
#include "../../scene_director.h"
|
#include "../../scene_director.h"
|
||||||
#include "totp_input_text.h"
|
#include "totp_input_text.h"
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../ui_controls.h"
|
#include "../../ui_controls.h"
|
||||||
#include "../../common_dialogs.h"
|
#include "../../common_dialogs.h"
|
||||||
#include <roll_value.h>
|
#include <roll_value.h>
|
||||||
#include "../../../types/nullable.h"
|
|
||||||
#include "../generate_token/totp_scene_generate_token.h"
|
#include "../generate_token/totp_scene_generate_token.h"
|
||||||
|
|
||||||
char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512", "Steam"};
|
char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512", "Steam"};
|
||||||
char* TOKEN_DIGITS_TEXT_LIST[] = {"5 digits", "6 digits", "8 digits"};
|
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 {
|
typedef enum {
|
||||||
TokenNameTextBox,
|
TokenNameTextBox,
|
||||||
@@ -36,7 +37,6 @@ typedef struct {
|
|||||||
InputTextSceneContext* token_secret_input_context;
|
InputTextSceneContext* token_secret_input_context;
|
||||||
InputTextSceneState* input_state;
|
InputTextSceneState* input_state;
|
||||||
uint32_t input_started_at;
|
uint32_t input_started_at;
|
||||||
TotpNullable_uint16_t current_token_index;
|
|
||||||
int16_t screen_y_offset;
|
int16_t screen_y_offset;
|
||||||
TokenHashAlgo algo;
|
TokenHashAlgo algo;
|
||||||
uint8_t digits_count_index;
|
uint8_t digits_count_index;
|
||||||
@@ -44,6 +44,13 @@ typedef struct {
|
|||||||
FuriString* duration_text;
|
FuriString* duration_text;
|
||||||
} SceneState;
|
} SceneState;
|
||||||
|
|
||||||
|
struct TotpAddContext {
|
||||||
|
SceneState* scene_state;
|
||||||
|
uint8_t* iv;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
|
||||||
|
|
||||||
static void on_token_name_user_comitted(InputTextSceneCallbackResult* result) {
|
static void on_token_name_user_comitted(InputTextSceneCallbackResult* result) {
|
||||||
SceneState* scene_state = result->callback_data;
|
SceneState* scene_state = result->callback_data;
|
||||||
free(scene_state->token_name);
|
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);
|
furi_string_printf(scene_state->duration_text, "%d sec.", scene_state->duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_scene_add_new_token_activate(
|
static TotpIteratorUpdateTokenResult add_token_handler(TokenInfo* tokenInfo, const void* context) {
|
||||||
PluginState* plugin_state,
|
const struct TotpAddContext* context_t = context;
|
||||||
const TokenAddEditSceneContext* 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));
|
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||||
furi_check(scene_state != NULL);
|
furi_check(scene_state != NULL);
|
||||||
plugin_state->current_scene_state = scene_state;
|
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 = TOTP_TOKEN_DURATION_DEFAULT;
|
||||||
scene_state->duration_text = furi_string_alloc();
|
scene_state->duration_text = furi_string_alloc();
|
||||||
update_duration_text(scene_state);
|
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) {
|
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:
|
case TokenDurationSelect:
|
||||||
break;
|
break;
|
||||||
case ConfirmButton: {
|
case ConfirmButton: {
|
||||||
TokenInfo* tokenInfo = token_info_alloc();
|
struct TotpAddContext add_context = {
|
||||||
bool token_secret_set = token_info_set_secret(
|
.iv = plugin_state->iv, .scene_state = scene_state};
|
||||||
tokenInfo,
|
TokenInfoIteratorContext* iterator_context =
|
||||||
scene_state->token_secret,
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
scene_state->token_secret_length,
|
TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(
|
||||||
PLAIN_TOKEN_ENCODING_BASE32,
|
iterator_context, &add_token_handler, &add_context);
|
||||||
&plugin_state->iv[0]);
|
|
||||||
|
|
||||||
if(token_secret_set) {
|
if(add_result == TotpIteratorUpdateTokenResultSuccess) {
|
||||||
tokenInfo->name = malloc(scene_state->token_name_length + 1);
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
furi_check(tokenInfo->name != NULL);
|
} else if(add_result == TotpIteratorUpdateTokenResultInvalidSecret) {
|
||||||
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);
|
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
@@ -305,7 +304,10 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
|
|||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
scene_state->selected_control = TokenSecretTextBox;
|
scene_state->selected_control = TokenSecretTextBox;
|
||||||
update_screen_y_offset(scene_state);
|
update_screen_y_offset(scene_state);
|
||||||
|
} else if(add_result == TotpIteratorUpdateTokenResultFileUpdateFailed) {
|
||||||
|
totp_dialogs_config_updating_error(plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -313,14 +315,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
if(!scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -4,13 +4,7 @@
|
|||||||
#include "../../../types/plugin_state.h"
|
#include "../../../types/plugin_state.h"
|
||||||
#include "../../../types/plugin_event.h"
|
#include "../../../types/plugin_event.h"
|
||||||
|
|
||||||
typedef struct {
|
void totp_scene_add_new_token_activate(PluginState* plugin_state);
|
||||||
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_render(Canvas* const canvas, 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);
|
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state);
|
||||||
void totp_scene_add_new_token_deactivate(PluginState* plugin_state);
|
void totp_scene_add_new_token_deactivate(PluginState* plugin_state);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include "../../../services/convert/convert.h"
|
#include "../../../services/convert/convert.h"
|
||||||
#include <roll_value.h>
|
#include <roll_value.h>
|
||||||
#include "../../../types/nullable.h"
|
|
||||||
#include "../../../features_config.h"
|
#include "../../../features_config.h"
|
||||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||||
@@ -40,21 +39,13 @@ typedef struct {
|
|||||||
bool badbt_enabled;
|
bool badbt_enabled;
|
||||||
#endif
|
#endif
|
||||||
uint8_t y_offset;
|
uint8_t y_offset;
|
||||||
TotpNullable_uint16_t current_token_index;
|
|
||||||
Control selected_control;
|
Control selected_control;
|
||||||
} SceneState;
|
} SceneState;
|
||||||
|
|
||||||
void totp_scene_app_settings_activate(
|
void totp_scene_app_settings_activate(PluginState* plugin_state) {
|
||||||
PluginState* plugin_state,
|
|
||||||
const AppSettingsSceneContext* context) {
|
|
||||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||||
furi_check(scene_state != NULL);
|
furi_check(scene_state != NULL);
|
||||||
plugin_state->current_scene_state = scene_state;
|
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_int;
|
||||||
float off_dec = modff(plugin_state->timezone_offset, &off_int);
|
float off_dec = modff(plugin_state->timezone_offset, &off_int);
|
||||||
@@ -281,8 +272,7 @@ bool totp_scene_app_settings_handle_event(
|
|||||||
AutomationMethodNone;
|
AutomationMethodNone;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(totp_config_file_update_user_settings(plugin_state) !=
|
if(!totp_config_file_update_user_settings(plugin_state)) {
|
||||||
TotpConfigFileUpdateSuccess) {
|
|
||||||
totp_dialogs_config_updating_error(plugin_state);
|
totp_dialogs_config_updating_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -294,25 +284,11 @@ bool totp_scene_app_settings_handle_event(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputKeyBack: {
|
case InputKeyBack: {
|
||||||
if(!scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -4,13 +4,7 @@
|
|||||||
#include "../../../types/plugin_state.h"
|
#include "../../../types/plugin_state.h"
|
||||||
#include "../../../types/plugin_event.h"
|
#include "../../../types/plugin_event.h"
|
||||||
|
|
||||||
typedef struct {
|
void totp_scene_app_settings_activate(PluginState* plugin_state);
|
||||||
uint16_t current_token_index;
|
|
||||||
} AppSettingsSceneContext;
|
|
||||||
|
|
||||||
void totp_scene_app_settings_activate(
|
|
||||||
PluginState* plugin_state,
|
|
||||||
const AppSettingsSceneContext* context);
|
|
||||||
void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state);
|
void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state);
|
||||||
bool totp_scene_app_settings_handle_event(
|
bool totp_scene_app_settings_handle_event(
|
||||||
const PluginEvent* const event,
|
const PluginEvent* const event,
|
||||||
|
|||||||
@@ -114,12 +114,18 @@ bool totp_scene_authenticate_handle_event(
|
|||||||
scene_state->code_length++;
|
scene_state->code_length++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputKeyOk:
|
case InputKeyOk: {
|
||||||
totp_crypto_seed_iv(plugin_state, &scene_state->code_input[0], scene_state->code_length);
|
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)) {
|
if(totp_crypto_verify_key(plugin_state)) {
|
||||||
FURI_LOG_D(LOGGING_TAG, "PIN is valid");
|
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 {
|
} else {
|
||||||
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
|
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
|
||||||
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
|
||||||
@@ -140,6 +146,7 @@ bool totp_scene_authenticate_handle_event(
|
|||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
if(scene_state->code_length > 0) {
|
if(scene_state->code_length > 0) {
|
||||||
scene_state->code_input[scene_state->code_length - 1] = 0;
|
scene_state->code_input[scene_state->code_length - 1] = 0;
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ typedef struct {
|
|||||||
} UiPrecalculatedDimensions;
|
} UiPrecalculatedDimensions;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t current_token_index;
|
|
||||||
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
|
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
|
||||||
TokenInfo* current_token;
|
|
||||||
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
||||||
NotificationMessage const** notification_sequence_new_token;
|
NotificationMessage const** notification_sequence_new_token;
|
||||||
NotificationMessage const** notification_sequence_automation;
|
NotificationMessage const** notification_sequence_automation;
|
||||||
@@ -128,19 +126,21 @@ static const NotificationSequence*
|
|||||||
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
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;
|
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||||
|
TokenInfoIteratorContext* iterator_context =
|
||||||
if(scene_state->current_token_index < plugin_state->tokens_count) {
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
scene_state->current_token =
|
if(totp_token_info_iterator_go_to(iterator_context, token_index)) {
|
||||||
list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
|
|
||||||
totp_generate_code_worker_notify(
|
totp_generate_code_worker_notify(
|
||||||
scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
|
scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) {
|
static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin_state) {
|
||||||
uint8_t code_length = scene_state->current_token->digits;
|
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 offset_x = scene_state->ui_precalculated_dimensions.code_offset_x;
|
||||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||||
uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc;
|
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) {
|
static void on_new_token_code_generated(bool time_left, void* context) {
|
||||||
const PluginState* plugin_state = 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;
|
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;
|
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||||
scene_state->ui_precalculated_dimensions.code_total_length =
|
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 =
|
scene_state->ui_precalculated_dimensions.code_offset_x =
|
||||||
(SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
|
(SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
|
||||||
scene_state->ui_precalculated_dimensions.code_offset_x_inc =
|
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;
|
PROGRESS_BAR_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_scene_generate_token_activate(
|
void totp_scene_generate_token_activate(PluginState* plugin_state) {
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||||
furi_check(scene_state != NULL);
|
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;
|
plugin_state->current_scene_state = scene_state;
|
||||||
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
|
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
|
||||||
@@ -254,10 +228,11 @@ void totp_scene_generate_token_activate(
|
|||||||
scene_state->last_code_update_sync);
|
scene_state->last_code_update_sync);
|
||||||
}
|
}
|
||||||
#endif
|
#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->generate_code_worker_context = totp_generate_code_worker_start(
|
||||||
scene_state->last_code,
|
scene_state->last_code,
|
||||||
&scene_state->current_token,
|
totp_token_info_iterator_get_current_token(iterator_context),
|
||||||
scene_state->last_code_update_sync,
|
scene_state->last_code_update_sync,
|
||||||
plugin_state->timezone_offset,
|
plugin_state->timezone_offset,
|
||||||
plugin_state->iv);
|
plugin_state->iv);
|
||||||
@@ -270,11 +245,14 @@ void totp_scene_generate_token_activate(
|
|||||||
&on_code_lifetime_updated_generated,
|
&on_code_lifetime_updated_generated,
|
||||||
scene_state);
|
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) {
|
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_draw_str_aligned(
|
||||||
canvas,
|
canvas,
|
||||||
SCREEN_WIDTH_CENTER,
|
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;
|
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
|
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) {
|
if(SCREEN_WIDTH - token_name_width > 18) {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas,
|
canvas,
|
||||||
@@ -303,22 +283,17 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
|||||||
SCREEN_HEIGHT_CENTER - 20,
|
SCREEN_HEIGHT_CENTER - 20,
|
||||||
AlignCenter,
|
AlignCenter,
|
||||||
AlignCenter,
|
AlignCenter,
|
||||||
scene_state->current_token->name);
|
token_name_cstr);
|
||||||
} else {
|
} else {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas,
|
canvas, 9, SCREEN_HEIGHT_CENTER - 20, AlignLeft, AlignCenter, token_name_cstr);
|
||||||
9,
|
|
||||||
SCREEN_HEIGHT_CENTER - 20,
|
|
||||||
AlignLeft,
|
|
||||||
AlignCenter,
|
|
||||||
scene_state->current_token->name);
|
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
canvas_draw_box(canvas, 0, SCREEN_HEIGHT_CENTER - 24, 9, 9);
|
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_draw_box(canvas, SCREEN_WIDTH - 10, SCREEN_HEIGHT_CENTER - 24, 9, 9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_totp_code(canvas, scene_state);
|
draw_totp_code(canvas, plugin_state);
|
||||||
|
|
||||||
canvas_draw_box(
|
canvas_draw_box(
|
||||||
canvas,
|
canvas,
|
||||||
@@ -326,11 +301,10 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
|||||||
SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
|
SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
|
||||||
scene_state->ui_precalculated_dimensions.progress_bar_width,
|
scene_state->ui_precalculated_dimensions.progress_bar_width,
|
||||||
PROGRESS_BAR_HEIGHT);
|
PROGRESS_BAR_HEIGHT);
|
||||||
|
if(totp_token_info_iterator_get_total_count(iterator_context) > 1) {
|
||||||
if(plugin_state->tokens_count > 1) {
|
|
||||||
canvas_draw_icon(canvas, 0, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_left_8x9);
|
canvas_draw_icon(canvas, 0, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_left_8x9);
|
||||||
canvas_draw_icon(
|
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
|
#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
|
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||||
if(plugin_state->automation_method & AutomationMethodBadBt &&
|
if(plugin_state->automation_method & AutomationMethodBadBt &&
|
||||||
plugin_state->bt_type_code_worker_context != NULL &&
|
plugin_state->bt_type_code_worker_context != NULL &&
|
||||||
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_draw_icon(
|
||||||
canvas,
|
canvas,
|
||||||
SCREEN_WIDTH_CENTER +
|
SCREEN_WIDTH_CENTER +
|
||||||
@@ -379,10 +353,12 @@ bool totp_scene_generate_token_handle_event(
|
|||||||
if(event->input.key == InputKeyDown &&
|
if(event->input.key == InputKeyDown &&
|
||||||
plugin_state->automation_method & AutomationMethodBadUsb) {
|
plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
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(
|
totp_usb_type_code_worker_notify(
|
||||||
scene_state->usb_type_code_worker_context,
|
scene_state->usb_type_code_worker_context,
|
||||||
TotpUsbTypeCodeWorkerEventType,
|
TotpUsbTypeCodeWorkerEventType,
|
||||||
scene_state->current_token->automation_features);
|
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||||
notification_message(
|
notification_message(
|
||||||
plugin_state->notification_app,
|
plugin_state->notification_app,
|
||||||
get_notification_sequence_automation(plugin_state, scene_state));
|
get_notification_sequence_automation(plugin_state, scene_state));
|
||||||
@@ -393,10 +369,12 @@ bool totp_scene_generate_token_handle_event(
|
|||||||
event->input.key == InputKeyUp &&
|
event->input.key == InputKeyUp &&
|
||||||
plugin_state->automation_method & AutomationMethodBadBt) {
|
plugin_state->automation_method & AutomationMethodBadBt) {
|
||||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
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(
|
totp_bt_type_code_worker_notify(
|
||||||
plugin_state->bt_type_code_worker_context,
|
plugin_state->bt_type_code_worker_context,
|
||||||
TotpBtTypeCodeWorkerEventType,
|
TotpBtTypeCodeWorkerEventType,
|
||||||
scene_state->current_token->automation_features);
|
totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
|
||||||
notification_message(
|
notification_message(
|
||||||
plugin_state->notification_app,
|
plugin_state->notification_app,
|
||||||
get_notification_sequence_automation(plugin_state, scene_state));
|
get_notification_sequence_automation(plugin_state, scene_state));
|
||||||
@@ -409,37 +387,43 @@ bool totp_scene_generate_token_handle_event(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state = (SceneState*)plugin_state->current_scene_state;
|
|
||||||
switch(event->input.key) {
|
switch(event->input.key) {
|
||||||
case InputKeyUp:
|
case InputKeyUp:
|
||||||
break;
|
break;
|
||||||
case InputKeyDown:
|
case InputKeyDown:
|
||||||
break;
|
break;
|
||||||
case InputKeyRight:
|
case InputKeyRight: {
|
||||||
totp_roll_value_uint16_t(
|
const TokenInfoIteratorContext* iterator_context =
|
||||||
&scene_state->current_token_index,
|
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,
|
1,
|
||||||
0,
|
0,
|
||||||
plugin_state->tokens_count - 1,
|
totp_token_info_iterator_get_total_count(iterator_context) - 1,
|
||||||
RollOverflowBehaviorRoll);
|
RollOverflowBehaviorRoll);
|
||||||
update_totp_params(plugin_state);
|
|
||||||
|
update_totp_params(plugin_state, current_token_index);
|
||||||
break;
|
break;
|
||||||
case InputKeyLeft:
|
}
|
||||||
totp_roll_value_uint16_t(
|
case InputKeyLeft: {
|
||||||
&scene_state->current_token_index,
|
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,
|
-1,
|
||||||
0,
|
0,
|
||||||
plugin_state->tokens_count - 1,
|
totp_token_info_iterator_get_total_count(iterator_context) - 1,
|
||||||
RollOverflowBehaviorRoll);
|
RollOverflowBehaviorRoll);
|
||||||
update_totp_params(plugin_state);
|
|
||||||
|
update_totp_params(plugin_state, current_token_index);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case InputKeyOk:
|
case InputKeyOk:
|
||||||
if(plugin_state->tokens_count == 0) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -4,13 +4,7 @@
|
|||||||
#include "../../../types/plugin_state.h"
|
#include "../../../types/plugin_state.h"
|
||||||
#include "../../../types/plugin_event.h"
|
#include "../../../types/plugin_event.h"
|
||||||
|
|
||||||
typedef struct {
|
void totp_scene_generate_token_activate(PluginState* plugin_state);
|
||||||
uint16_t current_token_index;
|
|
||||||
} GenerateTokenSceneContext;
|
|
||||||
|
|
||||||
void totp_scene_generate_token_activate(
|
|
||||||
PluginState* plugin_state,
|
|
||||||
const GenerateTokenSceneContext* context);
|
|
||||||
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state);
|
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state);
|
||||||
bool totp_scene_generate_token_handle_event(
|
bool totp_scene_generate_token_handle_event(
|
||||||
const PluginEvent* const event,
|
const PluginEvent* const event,
|
||||||
|
|||||||
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
@@ -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 "../../constants.h"
|
||||||
#include "../../scene_director.h"
|
#include "../../scene_director.h"
|
||||||
#include "../../../services/config/config.h"
|
#include "../../../services/config/config.h"
|
||||||
#include <linked_list.h>
|
|
||||||
#include "../../../types/token_info.h"
|
#include "../../../types/token_info.h"
|
||||||
#include "../generate_token/totp_scene_generate_token.h"
|
#include "../generate_token/totp_scene_generate_token.h"
|
||||||
#include "../add_new_token/totp_scene_add_new_token.h"
|
#include "../add_new_token/totp_scene_add_new_token.h"
|
||||||
#include "../app_settings/totp_app_settings.h"
|
#include "../app_settings/totp_app_settings.h"
|
||||||
#include "../../../types/nullable.h"
|
|
||||||
#include <roll_value.h>
|
#include <roll_value.h>
|
||||||
|
|
||||||
#define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3)
|
#define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3)
|
||||||
@@ -21,25 +19,19 @@ typedef enum { AddNewToken, DeleteToken, AppSettings } Control;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Control selected_control;
|
Control selected_control;
|
||||||
TotpNullable_uint16_t current_token_index;
|
|
||||||
} SceneState;
|
} SceneState;
|
||||||
|
|
||||||
void totp_scene_token_menu_activate(
|
void totp_scene_token_menu_activate(PluginState* plugin_state) {
|
||||||
PluginState* plugin_state,
|
|
||||||
const TokenMenuSceneContext* context) {
|
|
||||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||||
furi_check(scene_state != NULL);
|
furi_check(scene_state != NULL);
|
||||||
plugin_state->current_scene_state = scene_state;
|
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) {
|
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||||
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_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(
|
ui_control_button_render(
|
||||||
canvas,
|
canvas,
|
||||||
SCREEN_WIDTH_CENTER - 36,
|
SCREEN_WIDTH_CENTER - 36,
|
||||||
@@ -95,22 +87,28 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(event->input.key) {
|
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(
|
totp_roll_value_uint8_t(
|
||||||
&scene_state->selected_control, -1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
&scene_state->selected_control, -1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
||||||
if(scene_state->selected_control == DeleteToken &&
|
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--;
|
scene_state->selected_control--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputKeyDown:
|
}
|
||||||
|
case InputKeyDown: {
|
||||||
|
const TokenInfoIteratorContext* iterator_context =
|
||||||
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
totp_roll_value_uint8_t(
|
totp_roll_value_uint8_t(
|
||||||
&scene_state->selected_control, 1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
&scene_state->selected_control, 1, AddNewToken, AppSettings, RollOverflowBehaviorRoll);
|
||||||
if(scene_state->selected_control == DeleteToken &&
|
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++;
|
scene_state->selected_control++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case InputKeyRight:
|
case InputKeyRight:
|
||||||
break;
|
break;
|
||||||
case InputKeyLeft:
|
case InputKeyLeft:
|
||||||
@@ -118,14 +116,7 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
|||||||
case InputKeyOk:
|
case InputKeyOk:
|
||||||
switch(scene_state->selected_control) {
|
switch(scene_state->selected_control) {
|
||||||
case AddNewToken: {
|
case AddNewToken: {
|
||||||
if(scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DeleteToken: {
|
case DeleteToken: {
|
||||||
@@ -142,34 +133,21 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
|||||||
DialogMessageButton dialog_result =
|
DialogMessageButton dialog_result =
|
||||||
dialog_message_show(plugin_state->dialogs_app, message);
|
dialog_message_show(plugin_state->dialogs_app, message);
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
|
TokenInfoIteratorContext* iterator_context =
|
||||||
|
totp_config_get_token_iterator_context(plugin_state);
|
||||||
if(dialog_result == DialogMessageButtonRight &&
|
if(dialog_result == DialogMessageButtonRight &&
|
||||||
!scene_state->current_token_index.is_null) {
|
totp_token_info_iterator_get_total_count(iterator_context) > 0) {
|
||||||
TokenInfo* tokenInfo = NULL;
|
if(!totp_token_info_iterator_remove_current_token_info(iterator_context)) {
|
||||||
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_dialogs_config_updating_error(plugin_state);
|
totp_dialogs_config_updating_error(plugin_state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
|
||||||
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AppSettings: {
|
case AppSettings: {
|
||||||
if(!scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -177,14 +155,7 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputKeyBack: {
|
case InputKeyBack: {
|
||||||
if(!scene_state->current_token_index.is_null) {
|
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -4,13 +4,7 @@
|
|||||||
#include "../../../types/plugin_state.h"
|
#include "../../../types/plugin_state.h"
|
||||||
#include "../../../types/plugin_event.h"
|
#include "../../../types/plugin_event.h"
|
||||||
|
|
||||||
typedef struct {
|
void totp_scene_token_menu_activate(PluginState* plugin_state);
|
||||||
uint16_t current_token_index;
|
|
||||||
} TokenMenuSceneContext;
|
|
||||||
|
|
||||||
void totp_scene_token_menu_activate(
|
|
||||||
PluginState* plugin_state,
|
|
||||||
const TokenMenuSceneContext* context);
|
|
||||||
void totp_scene_token_menu_render(Canvas* const canvas, 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);
|
bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginState* plugin_state);
|
||||||
void totp_scene_token_menu_deactivate(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
|
* @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_bt_hid.h>
|
||||||
#include <furi_hal_version.h>
|
#include <furi_hal_version.h>
|
||||||
#include <bt/bt_service/bt_i.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 <storage/storage.h>
|
||||||
#include "../../types/common.h"
|
#include "../../types/common.h"
|
||||||
#include "../../types/token_info.h"
|
#include "../../types/token_info.h"
|
||||||
#include "../type_code_common.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")
|
#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() {
|
static inline bool totp_type_code_worker_stop_requested() {
|
||||||
return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop;
|
return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop;
|
||||||
}
|
}
|
||||||
@@ -198,3 +224,7 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) {
|
|||||||
|
|
||||||
free(context);
|
free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool totp_bt_type_code_worker_is_advertising(const TotpBtTypeCodeWorkerContext* context) {
|
||||||
|
return context->is_advertising;
|
||||||
|
}
|
||||||
@@ -1,50 +1,79 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdint.h>
|
||||||
#include <furi/core/thread.h>
|
#include <stdbool.h>
|
||||||
#include <furi/core/mutex.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 uint8_t TotpBtTypeCodeWorkerEvent;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct TotpBtTypeCodeWorkerContext 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
|
|
||||||
} TotpBtTypeCodeWorkerContext;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bluetooth token input automation worker events
|
||||||
|
*/
|
||||||
enum TotpBtTypeCodeWorkerEvents {
|
enum TotpBtTypeCodeWorkerEvents {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserved, should not be used anywhere
|
||||||
|
*/
|
||||||
TotpBtTypeCodeWorkerEventReserved = 0b00,
|
TotpBtTypeCodeWorkerEventReserved = 0b00,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop worker
|
||||||
|
*/
|
||||||
TotpBtTypeCodeWorkerEventStop = 0b01,
|
TotpBtTypeCodeWorkerEventStop = 0b01,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trigger token input automation
|
||||||
|
*/
|
||||||
TotpBtTypeCodeWorkerEventType = 0b10
|
TotpBtTypeCodeWorkerEventType = 0b10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes bluetooth token input automation worker
|
||||||
|
* @return worker context
|
||||||
|
*/
|
||||||
TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
|
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);
|
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(
|
void totp_bt_type_code_worker_start(
|
||||||
TotpBtTypeCodeWorkerContext* context,
|
TotpBtTypeCodeWorkerContext* context,
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync);
|
FuriMutex* code_buffer_sync);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops bluetooth token input automation worker
|
||||||
|
* @param context worker context
|
||||||
|
*/
|
||||||
void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* 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(
|
void totp_bt_type_code_worker_notify(
|
||||||
TotpBtTypeCodeWorkerContext* context,
|
TotpBtTypeCodeWorkerContext* context,
|
||||||
TotpBtTypeCodeWorkerEvent event,
|
TotpBtTypeCodeWorkerEvent event,
|
||||||
uint8_t flags);
|
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 "generate_totp_code.h"
|
||||||
|
#include <furi/core/thread.h>
|
||||||
#include "../../services/crypto/crypto.h"
|
#include "../../services/crypto/crypto.h"
|
||||||
#include "../../services/totp/totp.h"
|
#include "../../services/totp/totp.h"
|
||||||
#include "../../services/convert/convert.h"
|
#include "../../services/convert/convert.h"
|
||||||
@@ -7,6 +8,19 @@
|
|||||||
|
|
||||||
#define ONE_SEC_MS (1000)
|
#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 const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -93,7 +107,7 @@ static int32_t totp_generate_worker_callback(void* context) {
|
|||||||
|
|
||||||
if(flags & TotpGenerateCodeWorkerEventStop) break;
|
if(flags & TotpGenerateCodeWorkerEventStop) break;
|
||||||
|
|
||||||
const TokenInfo* token_info = *(t_context->token_info);
|
const TokenInfo* token_info = t_context->token_info;
|
||||||
if(token_info == NULL) {
|
if(token_info == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -127,7 +141,7 @@ static int32_t totp_generate_worker_callback(void* context) {
|
|||||||
|
|
||||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
TokenInfo** token_info,
|
const TokenInfo* token_info,
|
||||||
FuriMutex* code_buffer_sync,
|
FuriMutex* code_buffer_sync,
|
||||||
float timezone_offset,
|
float timezone_offset,
|
||||||
uint8_t* iv) {
|
uint8_t* iv) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <furi/core/thread.h>
|
|
||||||
#include <furi/core/mutex.h>
|
#include <furi/core/mutex.h>
|
||||||
#include "../../types/token_info.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_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context);
|
||||||
typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
|
typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct TotpGenerateCodeWorkerContext TotpGenerateCodeWorkerContext;
|
||||||
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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate token worker events
|
||||||
|
*/
|
||||||
enum TotGenerateCodeWorkerEvents {
|
enum TotGenerateCodeWorkerEvents {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserved, should not be used anywhere
|
||||||
|
*/
|
||||||
TotpGenerateCodeWorkerEventReserved = 0b00,
|
TotpGenerateCodeWorkerEventReserved = 0b00,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop worker
|
||||||
|
*/
|
||||||
TotpGenerateCodeWorkerEventStop = 0b01,
|
TotpGenerateCodeWorkerEventStop = 0b01,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trigger token input automation
|
||||||
|
*/
|
||||||
TotpGenerateCodeWorkerEventForceUpdate = 0b10
|
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(
|
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
TokenInfo** token_info,
|
const TokenInfo* token_info,
|
||||||
FuriMutex* code_buffer_sync,
|
FuriMutex* code_buffer_sync,
|
||||||
float timezone_offset,
|
float timezone_offset,
|
||||||
uint8_t* iv);
|
uint8_t* iv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops generate code worker
|
||||||
|
* @param context worker context
|
||||||
|
*/
|
||||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* 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(
|
void totp_generate_code_worker_notify(
|
||||||
TotpGenerateCodeWorkerContext* context,
|
TotpGenerateCodeWorkerContext* context,
|
||||||
TotpGenerateCodeWorkerEvent event);
|
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(
|
void totp_generate_code_worker_set_code_generated_handler(
|
||||||
TotpGenerateCodeWorkerContext* context,
|
TotpGenerateCodeWorkerContext* context,
|
||||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||||
void* on_new_code_generated_handler_context);
|
void* on_new_code_generated_handler_context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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(
|
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||||
TotpGenerateCodeWorkerContext* context,
|
TotpGenerateCodeWorkerContext* context,
|
||||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ static const uint8_t hid_number_keys[] = {
|
|||||||
HID_KEYBOARD_Z};
|
HID_KEYBOARD_Z};
|
||||||
|
|
||||||
static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
||||||
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
|
if(features & TokenAutomationFeatureTypeSlower) {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ static uint32_t get_keystroke_delay(TokenAutomationFeature features) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_keypress_delay(TokenAutomationFeature features) {
|
static uint32_t get_keypress_delay(TokenAutomationFeature features) {
|
||||||
if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) {
|
if(features & TokenAutomationFeatureTypeSlower) {
|
||||||
return 60;
|
return 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,13 +64,13 @@ void totp_type_code_worker_execute_automation(
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(features & TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END) {
|
if(features & TokenAutomationFeatureEnterAtTheEnd) {
|
||||||
furi_delay_ms(get_keystroke_delay(features));
|
furi_delay_ms(get_keystroke_delay(features));
|
||||||
totp_type_code_worker_press_key(
|
totp_type_code_worker_press_key(
|
||||||
HID_KEYBOARD_RETURN, key_press_fn, key_release_fn, features);
|
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));
|
furi_delay_ms(get_keystroke_delay(features));
|
||||||
totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, 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);
|
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(
|
void totp_type_code_worker_execute_automation(
|
||||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
#include "usb_type_code.h"
|
#include "usb_type_code.h"
|
||||||
|
#include <furi_hal_usb.h>
|
||||||
#include <furi_hal_usb_hid.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 "../../services/convert/convert.h"
|
||||||
#include "../../types/token_info.h"
|
#include "../../types/token_info.h"
|
||||||
#include "../type_code_common.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) {
|
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
||||||
if(context->usb_mode_prev != NULL) {
|
if(context->usb_mode_prev != NULL) {
|
||||||
furi_hal_usb_set_config(context->usb_mode_prev, NULL);
|
furi_hal_usb_set_config(context->usb_mode_prev, NULL);
|
||||||
|
|||||||
@@ -1,34 +1,58 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdint.h>
|
||||||
#include <furi/core/thread.h>
|
#include <stdbool.h>
|
||||||
#include <furi/core/mutex.h>
|
#include <furi/core/mutex.h>
|
||||||
#include <furi/core/kernel.h>
|
|
||||||
#include <furi/core/check.h>
|
|
||||||
#include <furi_hal_usb.h>
|
|
||||||
|
|
||||||
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct TotpUsbTypeCodeWorkerContext TotpUsbTypeCodeWorkerContext;
|
||||||
char* code_buffer;
|
|
||||||
uint8_t code_buffer_size;
|
|
||||||
uint8_t flags;
|
|
||||||
FuriThread* thread;
|
|
||||||
FuriMutex* code_buffer_sync;
|
|
||||||
FuriHalUsbInterface* usb_mode_prev;
|
|
||||||
} TotpUsbTypeCodeWorkerContext;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB token input automation worker events
|
||||||
|
*/
|
||||||
enum TotpUsbTypeCodeWorkerEvents {
|
enum TotpUsbTypeCodeWorkerEvents {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserved, should not be used anywhere
|
||||||
|
*/
|
||||||
TotpUsbTypeCodeWorkerEventReserved = 0b00,
|
TotpUsbTypeCodeWorkerEventReserved = 0b00,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop worker
|
||||||
|
*/
|
||||||
TotpUsbTypeCodeWorkerEventStop = 0b01,
|
TotpUsbTypeCodeWorkerEventStop = 0b01,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trigger token input automation
|
||||||
|
*/
|
||||||
TotpUsbTypeCodeWorkerEventType = 0b10
|
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(
|
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||||
char* code_buffer,
|
char* code_buffer,
|
||||||
uint8_t code_buffer_size,
|
uint8_t code_buffer_size,
|
||||||
FuriMutex* code_buffer_sync);
|
FuriMutex* code_buffer_sync);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops USB token input automation worker
|
||||||
|
* @param context worker context
|
||||||
|
*/
|
||||||
void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* 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(
|
void totp_usb_type_code_worker_notify(
|
||||||
TotpUsbTypeCodeWorkerContext* context,
|
TotpUsbTypeCodeWorkerContext* context,
|
||||||
TotpUsbTypeCodeWorkerEvent event,
|
TotpUsbTypeCodeWorkerEvent event,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
|
|||||||
&ws_protocol_auriol_th,
|
&ws_protocol_auriol_th,
|
||||||
&ws_protocol_oregon_v1,
|
&ws_protocol_oregon_v1,
|
||||||
&ws_protocol_tx_8300,
|
&ws_protocol_tx_8300,
|
||||||
|
&ws_protocol_wendox_w6726,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SubGhzProtocolRegistry weather_station_protocol_registry = {
|
const SubGhzProtocolRegistry weather_station_protocol_registry = {
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
#include "auriol_hg0601a.h"
|
#include "auriol_hg0601a.h"
|
||||||
#include "oregon_v1.h"
|
#include "oregon_v1.h"
|
||||||
#include "tx_8300.h"
|
#include "tx_8300.h"
|
||||||
|
#include "wendox_w6726.h"
|
||||||
|
|
||||||
extern const SubGhzProtocolRegistry weather_station_protocol_registry;
|
extern const SubGhzProtocolRegistry weather_station_protocol_registry;
|
||||||
|
|||||||
299
applications/external/weather_station/protocols/wendox_w6726.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
#include "wendox_w6726.h"
|
||||||
|
|
||||||
|
#define TAG "WSProtocolWendoxW6726"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wendox W6726
|
||||||
|
*
|
||||||
|
* Temperature -50°Ñ to +70°Ñ
|
||||||
|
* _ _ _ __ _
|
||||||
|
* _| |___| |___| |___ ... | |_| |__...._______________
|
||||||
|
* preamble data guard time
|
||||||
|
*
|
||||||
|
* 3 reps every 3 minutes
|
||||||
|
* in the first message 11 bytes of the preamble in the rest by 7
|
||||||
|
*
|
||||||
|
* bit 0: 1955-hi, 5865-lo
|
||||||
|
* bit 1: 5865-hi, 1955-lo
|
||||||
|
* guard time: 12*1955+(lo last bit)
|
||||||
|
* data: 29 bit
|
||||||
|
*
|
||||||
|
* IIIII | ZTTTTTTTTT | uuuuuuuBuu | CCCC
|
||||||
|
*
|
||||||
|
* I: identification;
|
||||||
|
* Z: temperature sign;
|
||||||
|
* T: temperature sign dependent +12 Ѱ;
|
||||||
|
* B: battery low; flag to indicate low battery voltage;
|
||||||
|
* C: CRC4 (polynomial = 0x9, start_data = 0xD);
|
||||||
|
* u: unknown;
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const SubGhzBlockConst ws_protocol_wendox_w6726_const = {
|
||||||
|
.te_short = 1955,
|
||||||
|
.te_long = 5865,
|
||||||
|
.te_delta = 300,
|
||||||
|
.min_count_bit_for_found = 29,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WSProtocolDecoderWendoxW6726 {
|
||||||
|
SubGhzProtocolDecoderBase base;
|
||||||
|
|
||||||
|
SubGhzBlockDecoder decoder;
|
||||||
|
WSBlockGeneric generic;
|
||||||
|
|
||||||
|
uint16_t header_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WSProtocolEncoderWendoxW6726 {
|
||||||
|
SubGhzProtocolEncoderBase base;
|
||||||
|
|
||||||
|
SubGhzProtocolBlockEncoder encoder;
|
||||||
|
WSBlockGeneric generic;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WendoxW6726DecoderStepReset = 0,
|
||||||
|
WendoxW6726DecoderStepCheckPreambule,
|
||||||
|
WendoxW6726DecoderStepSaveDuration,
|
||||||
|
WendoxW6726DecoderStepCheckDuration,
|
||||||
|
} WendoxW6726DecoderStep;
|
||||||
|
|
||||||
|
const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder = {
|
||||||
|
.alloc = ws_protocol_decoder_wendox_w6726_alloc,
|
||||||
|
.free = ws_protocol_decoder_wendox_w6726_free,
|
||||||
|
|
||||||
|
.feed = ws_protocol_decoder_wendox_w6726_feed,
|
||||||
|
.reset = ws_protocol_decoder_wendox_w6726_reset,
|
||||||
|
|
||||||
|
.get_hash_data = ws_protocol_decoder_wendox_w6726_get_hash_data,
|
||||||
|
.serialize = ws_protocol_decoder_wendox_w6726_serialize,
|
||||||
|
.deserialize = ws_protocol_decoder_wendox_w6726_deserialize,
|
||||||
|
.get_string = ws_protocol_decoder_wendox_w6726_get_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder = {
|
||||||
|
.alloc = NULL,
|
||||||
|
.free = NULL,
|
||||||
|
|
||||||
|
.deserialize = NULL,
|
||||||
|
.stop = NULL,
|
||||||
|
.yield = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocol ws_protocol_wendox_w6726 = {
|
||||||
|
.name = WS_PROTOCOL_WENDOX_W6726_NAME,
|
||||||
|
.type = SubGhzProtocolWeatherStation,
|
||||||
|
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
|
||||||
|
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
|
||||||
|
|
||||||
|
.decoder = &ws_protocol_wendox_w6726_decoder,
|
||||||
|
.encoder = &ws_protocol_wendox_w6726_encoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment) {
|
||||||
|
UNUSED(environment);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = malloc(sizeof(WSProtocolDecoderWendoxW6726));
|
||||||
|
instance->base.protocol = &ws_protocol_wendox_w6726;
|
||||||
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_free(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_reset(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ws_protocol_wendox_w6726_check(WSProtocolDecoderWendoxW6726* instance) {
|
||||||
|
if(!instance->decoder.decode_data) return false;
|
||||||
|
uint8_t msg[] = {
|
||||||
|
instance->decoder.decode_data >> 28,
|
||||||
|
instance->decoder.decode_data >> 20,
|
||||||
|
instance->decoder.decode_data >> 12,
|
||||||
|
instance->decoder.decode_data >> 4};
|
||||||
|
|
||||||
|
uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
|
||||||
|
return (crc == (instance->decoder.decode_data & 0x0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analysis of received data
|
||||||
|
* @param instance Pointer to a WSBlockGeneric* instance
|
||||||
|
*/
|
||||||
|
static void ws_protocol_wendox_w6726_remote_controller(WSBlockGeneric* instance) {
|
||||||
|
instance->id = (instance->data >> 24) & 0xFF;
|
||||||
|
instance->battery_low = (instance->data >> 6) & 1;
|
||||||
|
instance->channel = WS_NO_CHANNEL;
|
||||||
|
|
||||||
|
if(((instance->data >> 23) & 1)) {
|
||||||
|
instance->temp = (float)(((instance->data >> 14) & 0x1FF) + 12) / 10.0f;
|
||||||
|
} else {
|
||||||
|
instance->temp = (float)((~(instance->data >> 14) & 0x1FF) + 1 - 12) / -10.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instance->temp < -50.0f) {
|
||||||
|
instance->temp = -50.0f;
|
||||||
|
} else if(instance->temp > 70.0f) {
|
||||||
|
instance->temp = 70.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->btn = WS_NO_BTN;
|
||||||
|
instance->humidity = WS_NO_HUMIDITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
|
||||||
|
switch(instance->decoder.parser_step) {
|
||||||
|
case WendoxW6726DecoderStepReset:
|
||||||
|
if((level) && (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepCheckPreambule;
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
instance->header_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepCheckPreambule:
|
||||||
|
if(level) {
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
} else {
|
||||||
|
if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 1) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2)) {
|
||||||
|
instance->header_count++;
|
||||||
|
} else if((instance->header_count > 4) && (instance->header_count < 12)) {
|
||||||
|
if((DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
instance->decoder.decode_data = 0;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepSaveDuration:
|
||||||
|
if(level) {
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepCheckDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepCheckDuration:
|
||||||
|
if(!level) {
|
||||||
|
if(duration >
|
||||||
|
ws_protocol_wendox_w6726_const.te_short + ws_protocol_wendox_w6726_const.te_long) {
|
||||||
|
if(DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else if(
|
||||||
|
DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
if((instance->decoder.decode_count_bit ==
|
||||||
|
ws_protocol_wendox_w6726_const.min_count_bit_for_found) &&
|
||||||
|
ws_protocol_wendox_w6726_check(instance)) {
|
||||||
|
instance->generic.data = instance->decoder.decode_data;
|
||||||
|
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||||
|
ws_protocol_wendox_w6726_remote_controller(&instance->generic);
|
||||||
|
if(instance->base.callback)
|
||||||
|
instance->base.callback(&instance->base, instance->base.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
} else if(
|
||||||
|
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 3)) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else if(
|
||||||
|
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return subghz_protocol_blocks_get_hash_data(
|
||||||
|
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return ws_block_generic_deserialize_check_count_bit(
|
||||||
|
&instance->generic,
|
||||||
|
flipper_format,
|
||||||
|
ws_protocol_wendox_w6726_const.min_count_bit_for_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
furi_string_printf(
|
||||||
|
output,
|
||||||
|
"%s %dbit\r\n"
|
||||||
|
"Key:0x%lX%08lX\r\n"
|
||||||
|
"Sn:0x%lX Ch:%d Bat:%d\r\n"
|
||||||
|
"Temp:%3.1f C Hum:%d%%",
|
||||||
|
instance->generic.protocol_name,
|
||||||
|
instance->generic.data_count_bit,
|
||||||
|
(uint32_t)(instance->generic.data >> 32),
|
||||||
|
(uint32_t)(instance->generic.data),
|
||||||
|
instance->generic.id,
|
||||||
|
instance->generic.channel,
|
||||||
|
instance->generic.battery_low,
|
||||||
|
(double)instance->generic.temp,
|
||||||
|
instance->generic.humidity);
|
||||||
|
}
|
||||||
80
applications/external/weather_station/protocols/wendox_w6726.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/base.h>
|
||||||
|
|
||||||
|
#include <lib/subghz/blocks/const.h>
|
||||||
|
#include <lib/subghz/blocks/decoder.h>
|
||||||
|
#include <lib/subghz/blocks/encoder.h>
|
||||||
|
#include "ws_generic.h"
|
||||||
|
#include <lib/subghz/blocks/math.h>
|
||||||
|
|
||||||
|
#define WS_PROTOCOL_WENDOX_W6726_NAME "Wendox W6726"
|
||||||
|
|
||||||
|
typedef struct WSProtocolDecoderWendoxW6726 WSProtocolDecoderWendoxW6726;
|
||||||
|
typedef struct WSProtocolEncoderWendoxW6726 WSProtocolEncoderWendoxW6726;
|
||||||
|
|
||||||
|
extern const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder;
|
||||||
|
extern const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder;
|
||||||
|
extern const SubGhzProtocol ws_protocol_wendox_w6726;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param environment Pointer to a SubGhzEnvironment instance
|
||||||
|
* @return WSProtocolDecoderWendoxW6726* pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_free(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset decoder WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_reset(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a raw sequence of levels and durations received from the air.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param level Signal level true-high false-low
|
||||||
|
* @param duration Duration of this level in, us
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting the hash sum of the last randomly received parcel.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @return hash Hash sum
|
||||||
|
*/
|
||||||
|
uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize data WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat instance
|
||||||
|
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize data WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat instance
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting a textual representation of the received data.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param output Resulting text
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output);
|
||||||
@@ -8,5 +8,5 @@ App(
|
|||||||
order=90,
|
order=90,
|
||||||
fap_icon="wifi_10px.png",
|
fap_icon="wifi_10px.png",
|
||||||
fap_category="WiFi",
|
fap_category="WiFi",
|
||||||
fap_libs=["assets"],
|
fap_icon_assets="assets",
|
||||||
)
|
)
|
||||||
|
|||||||
BIN
applications/external/wifi_marauder_companion/assets/DolphinCommon_56x48.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
applications/external/wifi_marauder_companion/assets/KeyBackspaceSelected_16x9.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/wifi_marauder_companion/assets/KeyBackspace_16x9.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/wifi_marauder_companion/assets/KeySaveSelected_24x11.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/wifi_marauder_companion/assets/KeySave_24x11.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/wifi_marauder_companion/assets/Text_10x10.png
vendored
Normal file
|
After Width: | Height: | Size: 158 B |
BIN
applications/external/wifi_marauder_companion/assets/WarningDolphin_45x42.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
46
applications/external/wifi_marauder_companion/file/sequential_file.c
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include "sequential_file.h"
|
||||||
|
|
||||||
|
char* sequential_file_resolve_path(
|
||||||
|
Storage* storage,
|
||||||
|
const char* dir,
|
||||||
|
const char* prefix,
|
||||||
|
const char* extension) {
|
||||||
|
if(storage == NULL || dir == NULL || prefix == NULL || extension == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char file_path[256];
|
||||||
|
int file_index = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(snprintf(
|
||||||
|
file_path, sizeof(file_path), "%s/%s_%d.%s", dir, prefix, file_index, extension) <
|
||||||
|
0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
file_index++;
|
||||||
|
} while(storage_file_exists(storage, file_path));
|
||||||
|
|
||||||
|
return strdup(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sequential_file_open(
|
||||||
|
Storage* storage,
|
||||||
|
File* file,
|
||||||
|
const char* dir,
|
||||||
|
const char* prefix,
|
||||||
|
const char* extension) {
|
||||||
|
if(storage == NULL || file == NULL || dir == NULL || prefix == NULL || extension == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* file_path = sequential_file_resolve_path(storage, dir, prefix, extension);
|
||||||
|
if(file_path == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
||||||
|
free(file_path);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
15
applications/external/wifi_marauder_companion/file/sequential_file.h
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <storage/storage.h>
|
||||||
|
|
||||||
|
char* sequential_file_resolve_path(
|
||||||
|
Storage* storage,
|
||||||
|
const char* dir,
|
||||||
|
const char* prefix,
|
||||||
|
const char* extension);
|
||||||
|
bool sequential_file_open(
|
||||||
|
Storage* storage,
|
||||||
|
File* file,
|
||||||
|
const char* dir,
|
||||||
|
const char* prefix,
|
||||||
|
const char* extension);
|
||||||
@@ -3,3 +3,12 @@ ADD_SCENE(wifi_marauder, console_output, ConsoleOutput)
|
|||||||
ADD_SCENE(wifi_marauder, text_input, TextInput)
|
ADD_SCENE(wifi_marauder, text_input, TextInput)
|
||||||
ADD_SCENE(wifi_marauder, settings_init, SettingsInit)
|
ADD_SCENE(wifi_marauder, settings_init, SettingsInit)
|
||||||
ADD_SCENE(wifi_marauder, log_viewer, LogViewer)
|
ADD_SCENE(wifi_marauder, log_viewer, LogViewer)
|
||||||
|
ADD_SCENE(wifi_marauder, user_input, UserInput)
|
||||||
|
ADD_SCENE(wifi_marauder, script_select, ScriptSelect)
|
||||||
|
ADD_SCENE(wifi_marauder, script_options, ScriptOptions)
|
||||||
|
ADD_SCENE(wifi_marauder, script_edit, ScriptEdit)
|
||||||
|
ADD_SCENE(wifi_marauder, script_settings, ScriptSettings)
|
||||||
|
ADD_SCENE(wifi_marauder, script_confirm_delete, ScriptConfirmDelete)
|
||||||
|
ADD_SCENE(wifi_marauder, script_stage_edit, ScriptStageEdit)
|
||||||
|
ADD_SCENE(wifi_marauder, script_stage_add, ScriptStageAdd)
|
||||||
|
ADD_SCENE(wifi_marauder, script_stage_edit_list, ScriptStageEditList)
|
||||||
|
|||||||
@@ -1,5 +1,34 @@
|
|||||||
#include "../wifi_marauder_app_i.h"
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
char* _wifi_marauder_get_prefix_from_cmd(const char* command) {
|
||||||
|
int end = strcspn(command, " ");
|
||||||
|
char* prefix = (char*)malloc(sizeof(char) * (end + 1));
|
||||||
|
strncpy(prefix, command, end);
|
||||||
|
prefix[end] = '\0';
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _wifi_marauder_is_save_pcaps_enabled(WifiMarauderApp* app) {
|
||||||
|
if(!app->ok_to_save_pcaps) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If it is a script that contains a sniff function
|
||||||
|
if(app->script != NULL) {
|
||||||
|
return wifi_marauder_script_has_stage(app->script, WifiMarauderScriptStageTypeSniffRaw) ||
|
||||||
|
wifi_marauder_script_has_stage(
|
||||||
|
app->script, WifiMarauderScriptStageTypeSniffBeacon) ||
|
||||||
|
wifi_marauder_script_has_stage(
|
||||||
|
app->script, WifiMarauderScriptStageTypeSniffDeauth) ||
|
||||||
|
wifi_marauder_script_has_stage(app->script, WifiMarauderScriptStageTypeSniffEsp) ||
|
||||||
|
wifi_marauder_script_has_stage(
|
||||||
|
app->script, WifiMarauderScriptStageTypeSniffPmkid) ||
|
||||||
|
wifi_marauder_script_has_stage(app->script, WifiMarauderScriptStageTypeSniffPwn);
|
||||||
|
}
|
||||||
|
// If it is a sniff function
|
||||||
|
return app->is_command && app->selected_tx_string &&
|
||||||
|
strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
|
void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
WifiMarauderApp* app = context;
|
WifiMarauderApp* app = context;
|
||||||
@@ -34,23 +63,29 @@ void wifi_marauder_console_output_handle_rx_packets_cb(uint8_t* buf, size_t len,
|
|||||||
void wifi_marauder_scene_console_output_on_enter(void* context) {
|
void wifi_marauder_scene_console_output_on_enter(void* context) {
|
||||||
WifiMarauderApp* app = context;
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
// Reset text box and set font
|
||||||
TextBox* text_box = app->text_box;
|
TextBox* text_box = app->text_box;
|
||||||
text_box_reset(app->text_box);
|
text_box_reset(text_box);
|
||||||
text_box_set_font(text_box, TextBoxFontText);
|
text_box_set_font(text_box, TextBoxFontText);
|
||||||
|
|
||||||
|
// Set focus on start or end
|
||||||
if(app->focus_console_start) {
|
if(app->focus_console_start) {
|
||||||
text_box_set_focus(text_box, TextBoxFocusStart);
|
text_box_set_focus(text_box, TextBoxFocusStart);
|
||||||
} else {
|
} else {
|
||||||
text_box_set_focus(text_box, TextBoxFocusEnd);
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set command-related messages
|
||||||
if(app->is_command) {
|
if(app->is_command) {
|
||||||
furi_string_reset(app->text_box_store);
|
furi_string_reset(app->text_box_store);
|
||||||
app->text_box_store_strlen = 0;
|
app->text_box_store_strlen = 0;
|
||||||
|
// Help message
|
||||||
if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) {
|
if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) {
|
||||||
const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION "\n";
|
const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION "\n";
|
||||||
furi_string_cat_str(app->text_box_store, help_msg);
|
furi_string_cat_str(app->text_box_store, help_msg);
|
||||||
app->text_box_store_strlen += strlen(help_msg);
|
app->text_box_store_strlen += strlen(help_msg);
|
||||||
}
|
}
|
||||||
|
// Stopscan message
|
||||||
if(app->show_stopscan_tip) {
|
if(app->show_stopscan_tip) {
|
||||||
const char* help_msg = "Press BACK to send stopscan\n";
|
const char* help_msg = "Press BACK to send stopscan\n";
|
||||||
furi_string_cat_str(app->text_box_store, help_msg);
|
furi_string_cat_str(app->text_box_store, help_msg);
|
||||||
@@ -58,13 +93,14 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set starting text - for "View Log from end", this will just be what was already in the text box store
|
// Set starting text
|
||||||
text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store));
|
text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store));
|
||||||
|
|
||||||
|
// Set scene state and switch view
|
||||||
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0);
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0);
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);
|
||||||
|
|
||||||
// Register callback to receive data
|
// Register callbacks to receive data
|
||||||
wifi_marauder_uart_set_handle_rx_data_cb(
|
wifi_marauder_uart_set_handle_rx_data_cb(
|
||||||
app->uart,
|
app->uart,
|
||||||
wifi_marauder_console_output_handle_rx_data_cb); // setup callback for general log rx thread
|
wifi_marauder_console_output_handle_rx_data_cb); // setup callback for general log rx thread
|
||||||
@@ -73,25 +109,53 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
|
|||||||
wifi_marauder_console_output_handle_rx_packets_cb); // setup callback for packets rx thread
|
wifi_marauder_console_output_handle_rx_packets_cb); // setup callback for packets rx thread
|
||||||
|
|
||||||
// Get ready to send command
|
// Get ready to send command
|
||||||
if(app->is_command && app->selected_tx_string) {
|
if((app->is_command && app->selected_tx_string) || app->script) {
|
||||||
|
const char* prefix =
|
||||||
|
strlen(app->selected_tx_string) > 0 ?
|
||||||
|
_wifi_marauder_get_prefix_from_cmd(app->selected_tx_string) : // Function name
|
||||||
|
app->script->name; // Script name
|
||||||
|
|
||||||
// Create files *before* sending command
|
// Create files *before* sending command
|
||||||
// (it takes time to iterate through the directory)
|
// (it takes time to iterate through the directory)
|
||||||
if(app->ok_to_save_logs) {
|
if(app->ok_to_save_logs) {
|
||||||
app->is_writing_log = true;
|
strcpy(
|
||||||
wifi_marauder_create_log_file(app);
|
app->log_file_path,
|
||||||
|
sequential_file_resolve_path(
|
||||||
|
app->storage, MARAUDER_APP_FOLDER_LOGS, prefix, "log"));
|
||||||
|
if(app->log_file_path != NULL) {
|
||||||
|
if(storage_file_open(
|
||||||
|
app->log_file, app->log_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||||
|
app->is_writing_log = true;
|
||||||
|
} else {
|
||||||
|
dialog_message_show_storage_error(app->dialogs, "Cannot open log file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dialog_message_show_storage_error(app->dialogs, "Cannot resolve log path");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is a sniff function, open the pcap file for recording
|
// If it is a sniff function or script, open the pcap file for recording
|
||||||
if(app->ok_to_save_pcaps &&
|
if(_wifi_marauder_is_save_pcaps_enabled(app)) {
|
||||||
strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0) {
|
if(sequential_file_open(
|
||||||
app->is_writing_pcap = true;
|
app->storage, app->capture_file, MARAUDER_APP_FOLDER_PCAPS, prefix, "pcap")) {
|
||||||
wifi_marauder_create_pcap_file(app);
|
app->is_writing_pcap = true;
|
||||||
|
} else {
|
||||||
|
dialog_message_show_storage_error(app->dialogs, "Cannot open pcap file");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send command with newline '\n'
|
// Send command with newline '\n'
|
||||||
wifi_marauder_uart_tx(
|
if(app->selected_tx_string) {
|
||||||
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
wifi_marauder_uart_tx(
|
||||||
wifi_marauder_uart_tx((uint8_t*)("\n"), 1);
|
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
||||||
|
wifi_marauder_uart_tx((uint8_t*)("\n"), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the script if the file with the script has been opened
|
||||||
|
if(app->script != NULL) {
|
||||||
|
app->script_worker = wifi_marauder_script_worker_alloc();
|
||||||
|
wifi_marauder_script_worker_start(app->script_worker, app->script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,14 +177,18 @@ bool wifi_marauder_scene_console_output_on_event(void* context, SceneManagerEven
|
|||||||
void wifi_marauder_scene_console_output_on_exit(void* context) {
|
void wifi_marauder_scene_console_output_on_exit(void* context) {
|
||||||
WifiMarauderApp* app = context;
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
// Automatically stop the scan when exiting view
|
||||||
|
if(app->is_command) {
|
||||||
|
wifi_marauder_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n"));
|
||||||
|
furi_delay_ms(50);
|
||||||
|
}
|
||||||
|
|
||||||
// Unregister rx callback
|
// Unregister rx callback
|
||||||
wifi_marauder_uart_set_handle_rx_data_cb(app->uart, NULL);
|
wifi_marauder_uart_set_handle_rx_data_cb(app->uart, NULL);
|
||||||
wifi_marauder_uart_set_handle_rx_data_cb(app->lp_uart, NULL);
|
wifi_marauder_uart_set_handle_rx_data_cb(app->lp_uart, NULL);
|
||||||
|
|
||||||
// Automatically stop the scan when exiting view
|
wifi_marauder_script_worker_free(app->script_worker);
|
||||||
if(app->is_command) {
|
app->script_worker = NULL;
|
||||||
wifi_marauder_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
app->is_writing_pcap = false;
|
app->is_writing_pcap = false;
|
||||||
if(app->capture_file && storage_file_is_open(app->capture_file)) {
|
if(app->capture_file && storage_file_is_open(app->capture_file)) {
|
||||||
|
|||||||
@@ -148,8 +148,10 @@ bool wifi_marauder_scene_log_viewer_on_event(void* context, SceneManagerEvent ev
|
|||||||
// Browse
|
// Browse
|
||||||
FuriString* predefined_filepath = furi_string_alloc_set_str(MARAUDER_APP_FOLDER_LOGS);
|
FuriString* predefined_filepath = furi_string_alloc_set_str(MARAUDER_APP_FOLDER_LOGS);
|
||||||
FuriString* selected_filepath = furi_string_alloc();
|
FuriString* selected_filepath = furi_string_alloc();
|
||||||
|
DialogsFileBrowserOptions browser_options;
|
||||||
|
dialog_file_browser_set_basic_options(&browser_options, ".log", &I_Text_10x10);
|
||||||
if(dialog_file_browser_show(
|
if(dialog_file_browser_show(
|
||||||
app->dialogs, selected_filepath, predefined_filepath, NULL)) {
|
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||||
strncpy(
|
strncpy(
|
||||||
app->log_file_path,
|
app->log_file_path,
|
||||||
furi_string_get_cstr(selected_filepath),
|
furi_string_get_cstr(selected_filepath),
|
||||||
|
|||||||
83
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_confirm_delete.c
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_confirm_delete_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_confirm_delete_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
app->widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"No",
|
||||||
|
wifi_marauder_scene_script_confirm_delete_widget_callback,
|
||||||
|
app);
|
||||||
|
widget_add_button_element(
|
||||||
|
app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"Yes",
|
||||||
|
wifi_marauder_scene_script_confirm_delete_widget_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
app->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Are you sure?");
|
||||||
|
widget_add_text_box_element(
|
||||||
|
app->widget,
|
||||||
|
0,
|
||||||
|
12,
|
||||||
|
128,
|
||||||
|
38,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
"The script will be\npermanently deleted",
|
||||||
|
false);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_confirm_delete_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
// get which button press: "Yes" or "No"
|
||||||
|
if(event.event == GuiButtonTypeRight) {
|
||||||
|
// Yes
|
||||||
|
if(app->script != NULL) {
|
||||||
|
char script_path[256];
|
||||||
|
snprintf(
|
||||||
|
script_path,
|
||||||
|
sizeof(script_path),
|
||||||
|
"%s/%s.json",
|
||||||
|
MARAUDER_APP_FOLDER_SCRIPTS,
|
||||||
|
app->script->name);
|
||||||
|
storage_simply_remove(app->storage, script_path);
|
||||||
|
wifi_marauder_script_free(app->script);
|
||||||
|
app->script = NULL;
|
||||||
|
|
||||||
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
dialog_message_set_text(message, "Deleted!", 88, 32, AlignCenter, AlignCenter);
|
||||||
|
dialog_message_set_icon(message, &I_DolphinCommon_56x48, 5, 6);
|
||||||
|
dialog_message_set_buttons(message, NULL, "Ok", NULL);
|
||||||
|
dialog_message_show(app->dialogs, message);
|
||||||
|
dialog_message_free(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_confirm_delete_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
widget_reset(app->widget);
|
||||||
|
}
|
||||||
125
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_edit.c
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_edit_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
WifiMarauderScriptStage* current_stage = app->script->first_stage;
|
||||||
|
uint32_t stage_index = 0;
|
||||||
|
|
||||||
|
while(current_stage != NULL && stage_index < index) {
|
||||||
|
current_stage = current_stage->next_stage;
|
||||||
|
stage_index++;
|
||||||
|
}
|
||||||
|
app->script_edit_selected_stage = current_stage;
|
||||||
|
|
||||||
|
if(app->script_edit_selected_stage != NULL) {
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptEdit, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptStageEdit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_edit_add_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptEdit, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptStageAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_edit_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
Submenu* submenu = app->submenu;
|
||||||
|
WifiMarauderScript* script = app->script;
|
||||||
|
submenu_set_header(submenu, script->name);
|
||||||
|
|
||||||
|
WifiMarauderScriptStage* current_stage = script->first_stage;
|
||||||
|
int stage_index = 0;
|
||||||
|
while(current_stage != NULL) {
|
||||||
|
switch(current_stage->type) {
|
||||||
|
case WifiMarauderScriptStageTypeScan:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Scan", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSelect:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Select", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeDeauth:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Deauth", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeProbe:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Probe", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffRaw:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Sniff raw", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffBeacon:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Sniff beacon",
|
||||||
|
stage_index,
|
||||||
|
wifi_marauder_scene_script_edit_callback,
|
||||||
|
app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffDeauth:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Sniff deauth",
|
||||||
|
stage_index,
|
||||||
|
wifi_marauder_scene_script_edit_callback,
|
||||||
|
app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffEsp:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Sniff esp", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffPmkid:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Sniff PMKID", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeSniffPwn:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Sniff pwn", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeBeaconList:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Beacon list", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeBeaconAp:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Beacon AP", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeExec:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Custom command",
|
||||||
|
stage_index,
|
||||||
|
wifi_marauder_scene_script_edit_callback,
|
||||||
|
app);
|
||||||
|
break;
|
||||||
|
case WifiMarauderScriptStageTypeDelay:
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Delay", stage_index, wifi_marauder_scene_script_edit_callback, app);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current_stage = current_stage->next_stage;
|
||||||
|
stage_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "[+] ADD STAGE", stage_index++, wifi_marauder_scene_script_edit_add_callback, app);
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptEdit));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_edit_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_edit_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
}
|
||||||
188
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_edit_list.c
vendored
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_add_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
// Creates new item
|
||||||
|
WifiMarauderScriptStageListItem* new_item =
|
||||||
|
(WifiMarauderScriptStageListItem*)malloc(sizeof(WifiMarauderScriptStageListItem));
|
||||||
|
new_item->value = malloc(64);
|
||||||
|
new_item->next_item = NULL;
|
||||||
|
|
||||||
|
if(app->script_stage_edit_first_item == NULL) {
|
||||||
|
app->script_stage_edit_first_item = new_item;
|
||||||
|
} else {
|
||||||
|
WifiMarauderScriptStageListItem* last_item = app->script_stage_edit_first_item;
|
||||||
|
while(last_item->next_item != NULL) {
|
||||||
|
last_item = last_item->next_item;
|
||||||
|
}
|
||||||
|
last_item->next_item = new_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEditList, index);
|
||||||
|
app->user_input_type = WifiMarauderUserInputTypeString;
|
||||||
|
app->user_input_string_reference = &new_item->value;
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneUserInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_stage_edit_list_deallocate_items(WifiMarauderApp* app) {
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
while(current_item != NULL) {
|
||||||
|
WifiMarauderScriptStageListItem* next_item = current_item->next_item;
|
||||||
|
free(current_item->value);
|
||||||
|
free(current_item);
|
||||||
|
current_item = next_item;
|
||||||
|
}
|
||||||
|
app->script_stage_edit_first_item = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_stage_edit_list_save_strings(WifiMarauderApp* app) {
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
int array_size = 0;
|
||||||
|
|
||||||
|
// Calculates the required array size
|
||||||
|
while(current_item != NULL) {
|
||||||
|
array_size++;
|
||||||
|
current_item = current_item->next_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reallocate the array of strings if necessary
|
||||||
|
if(*app->script_stage_edit_string_count_reference < array_size) {
|
||||||
|
*app->script_stage_edit_strings_reference =
|
||||||
|
realloc(*app->script_stage_edit_strings_reference, array_size * sizeof(char*));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills the array of strings
|
||||||
|
current_item = app->script_stage_edit_first_item;
|
||||||
|
int i = 0;
|
||||||
|
while(current_item != NULL) {
|
||||||
|
char* current_str = malloc(strlen(current_item->value) + 1);
|
||||||
|
strncpy(current_str, current_item->value, strlen(current_item->value) + 1);
|
||||||
|
(*app->script_stage_edit_strings_reference)[i] = current_str;
|
||||||
|
current_item = current_item->next_item;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*app->script_stage_edit_string_count_reference = array_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_stage_edit_list_save_numbers(WifiMarauderApp* app) {
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
int array_size = 0;
|
||||||
|
|
||||||
|
// Calculates the required array size
|
||||||
|
while(current_item != NULL) {
|
||||||
|
array_size++;
|
||||||
|
current_item = current_item->next_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reallocate the array of integers if necessary
|
||||||
|
if(*app->script_stage_edit_number_count_reference < array_size) {
|
||||||
|
*app->script_stage_edit_numbers_reference =
|
||||||
|
realloc(*app->script_stage_edit_numbers_reference, array_size * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills the array of integers
|
||||||
|
current_item = app->script_stage_edit_first_item;
|
||||||
|
int i = 0;
|
||||||
|
while(current_item != NULL) {
|
||||||
|
(*app->script_stage_edit_numbers_reference)[i] = atoi(current_item->value);
|
||||||
|
current_item = current_item->next_item;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*app->script_stage_edit_number_count_reference = array_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_save_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
if(app->script_stage_edit_strings_reference != NULL &&
|
||||||
|
app->script_stage_edit_string_count_reference != NULL) {
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_save_strings(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(app->script_stage_edit_numbers_reference != NULL &&
|
||||||
|
app->script_stage_edit_number_count_reference != NULL) {
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_save_numbers(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_deallocate_items(app);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_clear_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_deallocate_items(app);
|
||||||
|
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[+] ADD ITEM",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_add_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[*] SAVE ITEMS",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_save_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[-] CLEAR LIST",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_clear_callback,
|
||||||
|
app);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_list_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
int item_index = 0;
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
|
||||||
|
while(current_item != NULL) {
|
||||||
|
submenu_add_item(app->submenu, current_item->value, item_index++, NULL, app);
|
||||||
|
current_item = current_item->next_item;
|
||||||
|
}
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[+] ADD ITEM",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_add_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[*] SAVE ITEMS",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_save_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
app->submenu,
|
||||||
|
"[-] CLEAR LIST",
|
||||||
|
99,
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_clear_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
app->submenu,
|
||||||
|
scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEditList));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_stage_edit_list_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_list_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
}
|
||||||
111
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_options.c
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexRun,
|
||||||
|
SubmenuIndexSettings,
|
||||||
|
SubmenuIndexEditStages,
|
||||||
|
SubmenuIndexSave,
|
||||||
|
SubmenuIndexDelete
|
||||||
|
};
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_options_save_script(WifiMarauderApp* app) {
|
||||||
|
char script_path[256];
|
||||||
|
snprintf(
|
||||||
|
script_path,
|
||||||
|
sizeof(script_path),
|
||||||
|
"%s/%s.json",
|
||||||
|
MARAUDER_APP_FOLDER_SCRIPTS,
|
||||||
|
app->script->name);
|
||||||
|
wifi_marauder_script_save_json(app->storage, script_path, app->script);
|
||||||
|
|
||||||
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
dialog_message_set_text(message, "Saved!", 88, 32, AlignCenter, AlignCenter);
|
||||||
|
dialog_message_set_icon(message, &I_DolphinCommon_56x48, 5, 6);
|
||||||
|
dialog_message_set_buttons(message, NULL, "Ok", NULL);
|
||||||
|
dialog_message_show(app->dialogs, message);
|
||||||
|
dialog_message_free(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_options_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
switch(index) {
|
||||||
|
case SubmenuIndexRun:
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptOptions, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
|
||||||
|
break;
|
||||||
|
case SubmenuIndexSettings:
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptOptions, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptSettings);
|
||||||
|
break;
|
||||||
|
case SubmenuIndexEditStages:
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptOptions, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptEdit);
|
||||||
|
break;
|
||||||
|
case SubmenuIndexSave:
|
||||||
|
wifi_marauder_scene_script_options_save_script(app);
|
||||||
|
break;
|
||||||
|
case SubmenuIndexDelete:
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptOptions, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptConfirmDelete);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_options_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
// If returning after confirming script deletion
|
||||||
|
if(app->script == NULL) {
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Submenu* submenu = app->submenu;
|
||||||
|
|
||||||
|
submenu_set_header(submenu, app->script->name);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "[>] RUN", SubmenuIndexRun, wifi_marauder_scene_script_options_callback, app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[S] SETTINGS",
|
||||||
|
SubmenuIndexSettings,
|
||||||
|
wifi_marauder_scene_script_options_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] EDIT STAGES",
|
||||||
|
SubmenuIndexEditStages,
|
||||||
|
wifi_marauder_scene_script_options_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "[*] SAVE", SubmenuIndexSave, wifi_marauder_scene_script_options_callback, app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[X] DELETE",
|
||||||
|
SubmenuIndexDelete,
|
||||||
|
wifi_marauder_scene_script_options_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu,
|
||||||
|
scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptOptions));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_options_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
wifi_marauder_script_free(app->script);
|
||||||
|
app->script = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_options_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
}
|
||||||
90
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_select.c
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_select_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
char script_path[256];
|
||||||
|
snprintf(
|
||||||
|
script_path,
|
||||||
|
sizeof(script_path),
|
||||||
|
"%s/%s.json",
|
||||||
|
MARAUDER_APP_FOLDER_SCRIPTS,
|
||||||
|
furi_string_get_cstr(app->script_list[index]));
|
||||||
|
|
||||||
|
app->script = wifi_marauder_script_parse_json(app->storage, script_path);
|
||||||
|
if(app->script) {
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptSelect, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_select_add_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptSelect, index);
|
||||||
|
|
||||||
|
app->user_input_type = WifiMarauderUserInputTypeFileName;
|
||||||
|
app->user_input_file_dir = strdup(MARAUDER_APP_FOLDER_SCRIPTS);
|
||||||
|
app->user_input_file_extension = strdup("json");
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneUserInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_select_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
Submenu* submenu = app->submenu;
|
||||||
|
|
||||||
|
File* dir_scripts = storage_file_alloc(app->storage);
|
||||||
|
if(storage_dir_open(dir_scripts, MARAUDER_APP_FOLDER_SCRIPTS)) {
|
||||||
|
FileInfo file_info;
|
||||||
|
char file_path[255];
|
||||||
|
app->script_list_count = 0;
|
||||||
|
// Goes through the files in the folder counting the ones that end with the json extension
|
||||||
|
while(storage_dir_read(dir_scripts, &file_info, file_path, 255)) {
|
||||||
|
app->script_list_count++;
|
||||||
|
}
|
||||||
|
if(app->script_list_count > 0) {
|
||||||
|
submenu_set_header(submenu, "Select a script:");
|
||||||
|
app->script_list = malloc(app->script_list_count * sizeof(FuriString*));
|
||||||
|
storage_dir_close(dir_scripts);
|
||||||
|
storage_dir_open(dir_scripts, MARAUDER_APP_FOLDER_SCRIPTS);
|
||||||
|
// Read the files again from the beginning, adding the scripts in the list
|
||||||
|
int script_index = 0;
|
||||||
|
while(storage_dir_read(dir_scripts, &file_info, file_path, 255)) {
|
||||||
|
app->script_list[script_index] = furi_string_alloc();
|
||||||
|
path_extract_filename_no_ext(file_path, app->script_list[script_index]);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
furi_string_get_cstr(app->script_list[script_index]),
|
||||||
|
script_index,
|
||||||
|
wifi_marauder_scene_script_select_callback,
|
||||||
|
app);
|
||||||
|
script_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
submenu_set_header(submenu, "No script found");
|
||||||
|
}
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "[+] ADD SCRIPT", 99, wifi_marauder_scene_script_select_add_callback, app);
|
||||||
|
storage_dir_close(dir_scripts);
|
||||||
|
}
|
||||||
|
storage_file_free(dir_scripts);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptSelect));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_select_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_select_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
|
||||||
|
for(int i = 0; i < app->script_list_count; i++) {
|
||||||
|
furi_string_free(app->script_list[i]);
|
||||||
|
}
|
||||||
|
free(app->script_list);
|
||||||
|
}
|
||||||
87
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_settings.c
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
enum ScriptSettingsOption {
|
||||||
|
ScriptSettingsOptionRepeat,
|
||||||
|
ScriptSettingsOptionSavePcap,
|
||||||
|
ScriptSettingsOptionEnableLed
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* option_values[3] = {"No", "Yes", "Default"};
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_settings_enter_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
// Accept script repeat value
|
||||||
|
if(index == ScriptSettingsOptionRepeat) {
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptSettings, index);
|
||||||
|
app->user_input_type = WifiMarauderUserInputTypeNumber;
|
||||||
|
app->user_input_number_reference = &app->script->repeat;
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneUserInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_marauder_scene_script_settings_change_callback(VariableItem* item) {
|
||||||
|
WifiMarauderApp* app = variable_item_get_context(item);
|
||||||
|
|
||||||
|
uint8_t current_option = variable_item_list_get_selected_item_index(app->var_item_list);
|
||||||
|
uint8_t option_value_index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
|
switch(current_option) {
|
||||||
|
case ScriptSettingsOptionSavePcap:
|
||||||
|
variable_item_set_current_value_text(item, option_values[option_value_index]);
|
||||||
|
app->script->save_pcap = option_value_index;
|
||||||
|
break;
|
||||||
|
case ScriptSettingsOptionEnableLed:
|
||||||
|
variable_item_set_current_value_text(item, option_values[option_value_index]);
|
||||||
|
app->script->enable_led = option_value_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_settings_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
VariableItemList* var_item_list = app->var_item_list;
|
||||||
|
variable_item_list_set_enter_callback(
|
||||||
|
app->var_item_list, wifi_marauder_scene_script_settings_enter_callback, app);
|
||||||
|
|
||||||
|
// Script repeat option
|
||||||
|
VariableItem* repeat_item = variable_item_list_add(app->var_item_list, "Repeat", 1, NULL, app);
|
||||||
|
char repeat_str[32];
|
||||||
|
snprintf(repeat_str, sizeof(repeat_str), "%d", app->script->repeat);
|
||||||
|
variable_item_set_current_value_text(repeat_item, repeat_str);
|
||||||
|
|
||||||
|
// Save PCAP option
|
||||||
|
VariableItem* save_pcap_item = variable_item_list_add(
|
||||||
|
app->var_item_list,
|
||||||
|
"Save PCAP",
|
||||||
|
3,
|
||||||
|
wifi_marauder_scene_script_settings_change_callback,
|
||||||
|
app);
|
||||||
|
variable_item_set_current_value_index(save_pcap_item, app->script->save_pcap);
|
||||||
|
variable_item_set_current_value_text(save_pcap_item, option_values[app->script->save_pcap]);
|
||||||
|
|
||||||
|
// Enable board LED option
|
||||||
|
VariableItem* enable_led_item = variable_item_list_add(
|
||||||
|
app->var_item_list,
|
||||||
|
"Enable LED",
|
||||||
|
3,
|
||||||
|
wifi_marauder_scene_script_settings_change_callback,
|
||||||
|
app);
|
||||||
|
variable_item_set_current_value_index(enable_led_item, app->script->enable_led);
|
||||||
|
variable_item_set_current_value_text(enable_led_item, option_values[app->script->enable_led]);
|
||||||
|
|
||||||
|
variable_item_list_set_selected_item(
|
||||||
|
var_item_list,
|
||||||
|
scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptSettings));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_settings_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_settings_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
variable_item_list_reset(app->var_item_list);
|
||||||
|
}
|
||||||
297
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_stage_add.c
vendored
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
// Scan
|
||||||
|
static void wifi_marauder_scene_script_stage_add_scan_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageScan* stage =
|
||||||
|
(WifiMarauderScriptStageScan*)malloc(sizeof(WifiMarauderScriptStageScan));
|
||||||
|
stage->type = WifiMarauderScriptScanTypeAp;
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SCAN;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeScan, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select
|
||||||
|
static void wifi_marauder_scene_script_stage_add_select_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSelect* stage =
|
||||||
|
(WifiMarauderScriptStageSelect*)malloc(sizeof(WifiMarauderScriptStageSelect));
|
||||||
|
stage->type = WifiMarauderScriptSelectTypeAp;
|
||||||
|
stage->filter = strdup("all");
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSelect, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deauth
|
||||||
|
static void wifi_marauder_scene_script_stage_add_deauth_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageDeauth* stage =
|
||||||
|
(WifiMarauderScriptStageDeauth*)malloc(sizeof(WifiMarauderScriptStageDeauth));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_DEAUTH;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeDeauth, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probe
|
||||||
|
static void wifi_marauder_scene_script_stage_add_probe_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageProbe* stage =
|
||||||
|
(WifiMarauderScriptStageProbe*)malloc(sizeof(WifiMarauderScriptStageProbe));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_PROBE;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeProbe, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff RAW
|
||||||
|
static void wifi_marauder_scene_script_stage_add_sniffraw_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffRaw* stage =
|
||||||
|
(WifiMarauderScriptStageSniffRaw*)malloc(sizeof(WifiMarauderScriptStageSniffRaw));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffRaw, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff Beacon
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffbeacon_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffBeacon* stage =
|
||||||
|
(WifiMarauderScriptStageSniffBeacon*)malloc(sizeof(WifiMarauderScriptStageSniffBeacon));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffBeacon, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff Deauth
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffdeauth_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffDeauth* stage =
|
||||||
|
(WifiMarauderScriptStageSniffDeauth*)malloc(sizeof(WifiMarauderScriptStageSniffDeauth));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffDeauth, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff Esp
|
||||||
|
static void wifi_marauder_scene_script_stage_add_sniffesp_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffEsp* stage =
|
||||||
|
(WifiMarauderScriptStageSniffEsp*)malloc(sizeof(WifiMarauderScriptStageSniffEsp));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffEsp, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff PMKID
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffpmkid_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffPmkid* stage =
|
||||||
|
(WifiMarauderScriptStageSniffPmkid*)malloc(sizeof(WifiMarauderScriptStageSniffPmkid));
|
||||||
|
stage->channel = 0;
|
||||||
|
stage->force_deauth = WifiMarauderScriptBooleanTrue;
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffPmkid, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sniff Pwn
|
||||||
|
static void wifi_marauder_scene_script_stage_add_sniffpwn_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageSniffPwn* stage =
|
||||||
|
(WifiMarauderScriptStageSniffPwn*)malloc(sizeof(WifiMarauderScriptStageSniffPwn));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_SNIFF;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeSniffPwn, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beacon list
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_add_beaconlist_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageBeaconList* stage =
|
||||||
|
(WifiMarauderScriptStageBeaconList*)malloc(sizeof(WifiMarauderScriptStageBeaconList));
|
||||||
|
stage->ssids = NULL;
|
||||||
|
stage->ssid_count = 0;
|
||||||
|
stage->random_ssids = 0;
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_BEACON;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeBeaconList, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beacon AP
|
||||||
|
static void wifi_marauder_scene_script_stage_add_beaconap_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageBeaconAp* stage =
|
||||||
|
(WifiMarauderScriptStageBeaconAp*)malloc(sizeof(WifiMarauderScriptStageBeaconAp));
|
||||||
|
stage->timeout = WIFI_MARAUDER_DEFAULT_TIMEOUT_BEACON;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeBeaconAp, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec
|
||||||
|
static void wifi_marauder_scene_script_stage_add_exec_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageExec* stage =
|
||||||
|
(WifiMarauderScriptStageExec*)malloc(sizeof(WifiMarauderScriptStageExec));
|
||||||
|
stage->command = NULL;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeExec, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
static void wifi_marauder_scene_script_stage_add_delay_callback(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
WifiMarauderScriptStageDelay* stage =
|
||||||
|
(WifiMarauderScriptStageDelay*)malloc(sizeof(WifiMarauderScriptStageDelay));
|
||||||
|
stage->timeout = 0;
|
||||||
|
|
||||||
|
wifi_marauder_script_add_stage(app->script, WifiMarauderScriptStageTypeDelay, stage);
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_add_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
Submenu* submenu = app->submenu;
|
||||||
|
submenu_set_header(submenu, "Add stage");
|
||||||
|
|
||||||
|
int menu_index = 0;
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "[+] Scan", menu_index++, wifi_marauder_scene_script_stage_add_scan_callback, app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Select",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_select_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Deauth",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_deauth_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Probe",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_probe_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff RAW",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffraw_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff Beacon",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffbeacon_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff Deauth",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffdeauth_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff Esp",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffesp_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff PMKID",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffpmkid_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Sniff Pwnagotchi",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_sniffpwn_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Beacon List",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_beaconlist_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Beacon AP",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_beaconap_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Custom command",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_exec_callback,
|
||||||
|
app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"[+] Delay",
|
||||||
|
menu_index++,
|
||||||
|
wifi_marauder_scene_script_stage_add_delay_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptEdit));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_stage_add_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_add_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
submenu_reset(app->submenu);
|
||||||
|
}
|
||||||
203
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_script_stage_edit.c
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_create_list_strings(
|
||||||
|
WifiMarauderApp* app,
|
||||||
|
char** strings,
|
||||||
|
int string_count) {
|
||||||
|
// Deallocates the existing list
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
while(current_item != NULL) {
|
||||||
|
WifiMarauderScriptStageListItem* next_item = current_item->next_item;
|
||||||
|
free(current_item->value);
|
||||||
|
free(current_item);
|
||||||
|
current_item = next_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new list with numbers
|
||||||
|
WifiMarauderScriptStageListItem* first_item = NULL;
|
||||||
|
WifiMarauderScriptStageListItem* previous_item = NULL;
|
||||||
|
for(int i = 0; i < string_count; i++) {
|
||||||
|
WifiMarauderScriptStageListItem* item = malloc(sizeof(WifiMarauderScriptStageListItem));
|
||||||
|
item->value = strdup(strings[i]);
|
||||||
|
item->next_item = NULL;
|
||||||
|
|
||||||
|
if(previous_item == NULL) {
|
||||||
|
first_item = item;
|
||||||
|
} else {
|
||||||
|
previous_item->next_item = item;
|
||||||
|
}
|
||||||
|
previous_item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
app->script_stage_edit_first_item = first_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_create_list_numbers(
|
||||||
|
WifiMarauderApp* app,
|
||||||
|
int* numbers,
|
||||||
|
int number_count) {
|
||||||
|
// Deallocates the existing list
|
||||||
|
WifiMarauderScriptStageListItem* current_item = app->script_stage_edit_first_item;
|
||||||
|
while(current_item != NULL) {
|
||||||
|
WifiMarauderScriptStageListItem* next_item = current_item->next_item;
|
||||||
|
free(current_item->value);
|
||||||
|
free(current_item);
|
||||||
|
current_item = next_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new list with numbers
|
||||||
|
WifiMarauderScriptStageListItem* first_item = NULL;
|
||||||
|
WifiMarauderScriptStageListItem* previous_item = NULL;
|
||||||
|
for(int i = 0; i < number_count; i++) {
|
||||||
|
char number_str[32];
|
||||||
|
snprintf(number_str, sizeof(number_str), "%d", numbers[i]);
|
||||||
|
|
||||||
|
WifiMarauderScriptStageListItem* item = malloc(sizeof(WifiMarauderScriptStageListItem));
|
||||||
|
item->value = strdup(number_str);
|
||||||
|
item->next_item = NULL;
|
||||||
|
|
||||||
|
if(previous_item == NULL) {
|
||||||
|
first_item = item;
|
||||||
|
} else {
|
||||||
|
previous_item->next_item = item;
|
||||||
|
}
|
||||||
|
previous_item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
app->script_stage_edit_first_item = first_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wifi_marauder_scene_script_stage_edit_list_enter_callback(void* context, uint32_t index) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
const WifiMarauderScriptMenuItem* menu_item = &app->script_stage_menu->items[index];
|
||||||
|
|
||||||
|
// Fixed delete item
|
||||||
|
if(index == app->script_stage_menu->num_items) {
|
||||||
|
uint32_t deleted_stage_index =
|
||||||
|
scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptEdit);
|
||||||
|
if(deleted_stage_index > 0) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
app->scene_manager, WifiMarauderSceneScriptEdit, deleted_stage_index - 1);
|
||||||
|
}
|
||||||
|
WifiMarauderScriptStage* previous_stage = NULL;
|
||||||
|
WifiMarauderScriptStage* current_stage = app->script->first_stage;
|
||||||
|
uint32_t current_stage_index = 0;
|
||||||
|
|
||||||
|
while(current_stage != NULL && current_stage_index < deleted_stage_index) {
|
||||||
|
previous_stage = current_stage;
|
||||||
|
current_stage = current_stage->next_stage;
|
||||||
|
current_stage_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the stage
|
||||||
|
if(current_stage != NULL) {
|
||||||
|
if(previous_stage != NULL) {
|
||||||
|
if(current_stage->next_stage != NULL) {
|
||||||
|
previous_stage->next_stage = current_stage->next_stage;
|
||||||
|
} else {
|
||||||
|
previous_stage->next_stage = NULL;
|
||||||
|
app->script->last_stage = previous_stage;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(current_stage->next_stage != NULL) {
|
||||||
|
app->script->first_stage = current_stage->next_stage;
|
||||||
|
} else {
|
||||||
|
app->script->first_stage = NULL;
|
||||||
|
app->script->last_stage = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app->script_edit_selected_stage = NULL;
|
||||||
|
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(menu_item->select_callback == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(menu_item->type == WifiMarauderScriptMenuItemTypeNumber) {
|
||||||
|
// Accepts user number input, assigning the value to the reference passed as a parameter
|
||||||
|
menu_item->select_callback(app);
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEdit, index);
|
||||||
|
app->user_input_type = WifiMarauderUserInputTypeNumber;
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneUserInput);
|
||||||
|
} else if(menu_item->type == WifiMarauderScriptMenuItemTypeString) {
|
||||||
|
// Accepts user string input, assigning the value to the reference passed as a parameter
|
||||||
|
menu_item->select_callback(app);
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEdit, index);
|
||||||
|
app->user_input_type = WifiMarauderUserInputTypeString;
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneUserInput);
|
||||||
|
} else if(menu_item->type == WifiMarauderScriptMenuItemTypeListString) {
|
||||||
|
// Accepts the strings that compose the list
|
||||||
|
menu_item->select_callback(app);
|
||||||
|
wifi_marauder_scene_script_stage_edit_create_list_strings(
|
||||||
|
app,
|
||||||
|
*app->script_stage_edit_strings_reference,
|
||||||
|
*app->script_stage_edit_string_count_reference);
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEdit, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptStageEditList);
|
||||||
|
} else if(menu_item->type == WifiMarauderScriptMenuItemTypeListNumber) {
|
||||||
|
// Accepts the numbers that compose the list
|
||||||
|
menu_item->select_callback(app);
|
||||||
|
wifi_marauder_scene_script_stage_edit_create_list_numbers(
|
||||||
|
app,
|
||||||
|
*app->script_stage_edit_numbers_reference,
|
||||||
|
*app->script_stage_edit_number_count_reference);
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEdit, index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptStageEditList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
VariableItemList* var_item_list = app->var_item_list;
|
||||||
|
|
||||||
|
variable_item_list_set_enter_callback(
|
||||||
|
app->var_item_list, wifi_marauder_scene_script_stage_edit_list_enter_callback, app);
|
||||||
|
app->script_stage_menu =
|
||||||
|
wifi_marauder_script_stage_menu_create(app->script_edit_selected_stage->type);
|
||||||
|
|
||||||
|
if(app->script_stage_menu->items != NULL) {
|
||||||
|
for(uint32_t i = 0; i < app->script_stage_menu->num_items; i++) {
|
||||||
|
WifiMarauderScriptMenuItem* stage_item = &app->script_stage_menu->items[i];
|
||||||
|
|
||||||
|
// Changes the list item to handle it in callbacks
|
||||||
|
VariableItem* list_item = variable_item_list_add(
|
||||||
|
app->var_item_list,
|
||||||
|
stage_item->name,
|
||||||
|
stage_item->num_options,
|
||||||
|
stage_item->change_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
variable_item_list_set_selected_item(app->var_item_list, i);
|
||||||
|
if(stage_item->setup_callback != NULL) {
|
||||||
|
stage_item->setup_callback(list_item);
|
||||||
|
}
|
||||||
|
if(stage_item->change_callback != NULL) {
|
||||||
|
stage_item->change_callback(list_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable_item_list_add(app->var_item_list, "[-] DELETE STAGE", 0, NULL, app);
|
||||||
|
|
||||||
|
variable_item_list_set_selected_item(
|
||||||
|
var_item_list,
|
||||||
|
scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneScriptStageEdit));
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_script_stage_edit_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_script_stage_edit_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
wifi_marauder_script_stage_menu_free(app->script_stage_menu);
|
||||||
|
app->script_stage_menu = NULL;
|
||||||
|
variable_item_list_reset(app->var_item_list);
|
||||||
|
}
|
||||||
@@ -127,6 +127,7 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = {
|
|||||||
{"Update", {"ota", "sd"}, 2, {"update -w", "update -s"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
|
{"Update", {"ota", "sd"}, 2, {"update -w", "update -s"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
|
||||||
{"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
|
{"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
|
||||||
{"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP},
|
{"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP},
|
||||||
|
{"Scripts", {""}, 1, {""}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
|
||||||
{"Save to flipper sdcard", // keep as last entry or change logic in callback below
|
{"Save to flipper sdcard", // keep as last entry or change logic in callback below
|
||||||
{""},
|
{""},
|
||||||
1,
|
1,
|
||||||
@@ -143,13 +144,6 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin
|
|||||||
furi_assert(index < NUM_MENU_ITEMS);
|
furi_assert(index < NUM_MENU_ITEMS);
|
||||||
const WifiMarauderItem* item = &items[index];
|
const WifiMarauderItem* item = &items[index];
|
||||||
|
|
||||||
if(index == NUM_MENU_ITEMS - 1) {
|
|
||||||
// "Save to flipper sdcard" special case - start SettingsInit widget
|
|
||||||
view_dispatcher_send_custom_event(
|
|
||||||
app->view_dispatcher, WifiMarauderEventStartSettingsInit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int selected_option_index = app->selected_option_index[index];
|
const int selected_option_index = app->selected_option_index[index];
|
||||||
furi_assert(selected_option_index < item->num_options_menu);
|
furi_assert(selected_option_index < item->num_options_menu);
|
||||||
app->selected_tx_string = item->actual_commands[selected_option_index];
|
app->selected_tx_string = item->actual_commands[selected_option_index];
|
||||||
@@ -167,6 +161,20 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select automation script
|
||||||
|
if(index == NUM_MENU_ITEMS - 2) {
|
||||||
|
view_dispatcher_send_custom_event(
|
||||||
|
app->view_dispatcher, WifiMarauderEventStartScriptSelect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index == NUM_MENU_ITEMS - 1) {
|
||||||
|
// "Save to flipper sdcard" special case - start SettingsInit widget
|
||||||
|
view_dispatcher_send_custom_event(
|
||||||
|
app->view_dispatcher, WifiMarauderEventStartSettingsInit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) :
|
bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) :
|
||||||
item->needs_keyboard;
|
item->needs_keyboard;
|
||||||
if(needs_keyboard) {
|
if(needs_keyboard) {
|
||||||
@@ -242,6 +250,10 @@ bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event)
|
|||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
|
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
|
||||||
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneLogViewer);
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneLogViewer);
|
||||||
|
} else if(event.event == WifiMarauderEventStartScriptSelect) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
|
||||||
|
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptSelect);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
|
|||||||
155
applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "../wifi_marauder_app_i.h"
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_user_input_validator_number_callback(
|
||||||
|
const char* text,
|
||||||
|
FuriString* error,
|
||||||
|
void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
for(int i = 0; text[i] != '\0'; i++) {
|
||||||
|
if(text[i] < '0' || text[i] > '9') {
|
||||||
|
furi_string_printf(error, "This is not\na valid\nnumber!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_user_input_validator_file_callback(
|
||||||
|
const char* text,
|
||||||
|
FuriString* error,
|
||||||
|
void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
if(strlen(text) == 0) {
|
||||||
|
furi_string_printf(error, "File name\ncannot be\nblank!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_user_input_ok_callback(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
File* file = NULL;
|
||||||
|
char* file_path = NULL;
|
||||||
|
|
||||||
|
switch(app->user_input_type) {
|
||||||
|
// Writes the string value of the reference
|
||||||
|
case WifiMarauderUserInputTypeString:
|
||||||
|
if(app->user_input_string_reference != NULL) {
|
||||||
|
strncpy(
|
||||||
|
*app->user_input_string_reference,
|
||||||
|
app->text_input_store,
|
||||||
|
strlen(app->text_input_store) + 1);
|
||||||
|
app->user_input_string_reference = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Writes the numerical value of the reference
|
||||||
|
case WifiMarauderUserInputTypeNumber:
|
||||||
|
if(app->user_input_number_reference != NULL) {
|
||||||
|
*app->user_input_number_reference = atoi(app->text_input_store);
|
||||||
|
app->user_input_number_reference = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Creates a file with the name entered by the user, if it does not exist
|
||||||
|
case WifiMarauderUserInputTypeFileName:
|
||||||
|
file = storage_file_alloc(app->storage);
|
||||||
|
// Use application directory if not specified
|
||||||
|
if(app->user_input_file_dir == NULL) {
|
||||||
|
app->user_input_file_dir = strdup(MARAUDER_APP_FOLDER);
|
||||||
|
}
|
||||||
|
if(app->user_input_file_extension != NULL) {
|
||||||
|
size_t file_path_len = strlen(app->user_input_file_dir) +
|
||||||
|
strlen(app->text_input_store) +
|
||||||
|
strlen(app->user_input_file_extension) + 3;
|
||||||
|
file_path = (char*)malloc(file_path_len);
|
||||||
|
snprintf(
|
||||||
|
file_path,
|
||||||
|
file_path_len,
|
||||||
|
"%s/%s.%s",
|
||||||
|
app->user_input_file_dir,
|
||||||
|
app->text_input_store,
|
||||||
|
app->user_input_file_extension);
|
||||||
|
} else {
|
||||||
|
size_t file_path_len =
|
||||||
|
strlen(app->user_input_file_dir) + strlen(app->text_input_store) + 2;
|
||||||
|
file_path = (char*)malloc(file_path_len);
|
||||||
|
snprintf(
|
||||||
|
file_path, file_path_len, "%s/%s", app->user_input_file_dir, app->text_input_store);
|
||||||
|
}
|
||||||
|
if(storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_NEW)) {
|
||||||
|
storage_file_close(file);
|
||||||
|
}
|
||||||
|
// Free memory
|
||||||
|
free(app->user_input_file_dir);
|
||||||
|
app->user_input_file_dir = NULL;
|
||||||
|
free(app->user_input_file_extension);
|
||||||
|
app->user_input_file_extension = NULL;
|
||||||
|
free(file_path);
|
||||||
|
storage_file_free(file);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_user_input_on_enter(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
|
||||||
|
switch(app->user_input_type) {
|
||||||
|
// Loads the string value of the reference
|
||||||
|
case WifiMarauderUserInputTypeString:
|
||||||
|
wifi_text_input_set_header_text(app->text_input, "Enter value:");
|
||||||
|
wifi_text_input_set_validator(app->text_input, NULL, app);
|
||||||
|
if(app->user_input_string_reference != NULL) {
|
||||||
|
strncpy(
|
||||||
|
app->text_input_store,
|
||||||
|
*app->user_input_string_reference,
|
||||||
|
strlen(*app->user_input_string_reference) + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Loads the numerical value of the reference
|
||||||
|
case WifiMarauderUserInputTypeNumber:
|
||||||
|
wifi_text_input_set_header_text(app->text_input, "Enter a valid number:");
|
||||||
|
wifi_text_input_set_validator(
|
||||||
|
app->text_input, wifi_marauder_scene_user_input_validator_number_callback, app);
|
||||||
|
if(app->user_input_number_reference != NULL) {
|
||||||
|
char number_str[32];
|
||||||
|
snprintf(number_str, sizeof(number_str), "%d", *app->user_input_number_reference);
|
||||||
|
strncpy(app->text_input_store, number_str, strlen(number_str) + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// File name
|
||||||
|
case WifiMarauderUserInputTypeFileName:
|
||||||
|
wifi_text_input_set_header_text(app->text_input, "Enter file name:");
|
||||||
|
wifi_text_input_set_validator(
|
||||||
|
app->text_input, wifi_marauder_scene_user_input_validator_file_callback, app);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scene_manager_previous_scene(app->scene_manager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_text_input_set_result_callback(
|
||||||
|
app->text_input,
|
||||||
|
wifi_marauder_scene_user_input_ok_callback,
|
||||||
|
app,
|
||||||
|
app->text_input_store,
|
||||||
|
WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE,
|
||||||
|
false);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewTextInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wifi_marauder_scene_user_input_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_marauder_scene_user_input_on_exit(void* context) {
|
||||||
|
WifiMarauderApp* app = context;
|
||||||
|
memset(app->text_input_store, 0, sizeof(app->text_input_store));
|
||||||
|
wifi_text_input_reset(app->text_input);
|
||||||
|
}
|
||||||