Skip to content

Commit 41c23ba

Browse files
authored
Implementation of #65 (#66)
* Initial implementation of #65
1 parent cd7c9c7 commit 41c23ba

File tree

11 files changed

+234
-35
lines changed

11 files changed

+234
-35
lines changed

cli/commands/add/add.c

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define TOTP_CLI_COMMAND_ADD_ARG_DIGITS "digits"
1515
#define TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX "-d"
1616
#define TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX "-u"
17+
#define TOTP_CLI_COMMAND_ADD_ARG_DURATION "duration"
18+
#define TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX "-l"
1719

1820
static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
1921
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
@@ -34,6 +36,16 @@ static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString
3436
return false;
3537
}
3638

39+
static bool args_read_uint8_and_trim(FuriString* args, uint8_t* value) {
40+
int int_value;
41+
if (!args_read_int_and_trim(args, &int_value) || int_value < 0 || int_value > UINT8_MAX) {
42+
return false;
43+
}
44+
45+
*value = (uint8_t)int_value;
46+
return true;
47+
}
48+
3749
void totp_cli_command_add_docopt_commands() {
3850
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD ", " TOTP_CLI_COMMAND_ADD_ALT
3951
", " TOTP_CLI_COMMAND_ADD_ALT2 " Add new token\r\n");
@@ -42,11 +54,11 @@ void totp_cli_command_add_docopt_commands() {
4254
void totp_cli_command_add_docopt_usage() {
4355
TOTP_CLI_PRINTF(
4456
" " TOTP_CLI_COMMAND_NAME
45-
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_ADD " | " TOTP_CLI_COMMAND_ADD_ALT " | " TOTP_CLI_COMMAND_ADD_ALT2) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_NAME) " " DOCOPT_OPTIONAL(
57+
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_ADD " | " TOTP_CLI_COMMAND_ADD_ALT " | " TOTP_CLI_COMMAND_ADD_ALT2) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_NAME) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_ALGO))) " " DOCOPT_OPTIONAL(
4658
DOCOPT_OPTION(
47-
TOTP_CLI_COMMAND_ADD_ARG_ALGO_PREFIX,
59+
TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
4860
DOCOPT_ARGUMENT(
49-
TOTP_CLI_COMMAND_ADD_ARG_ALGO))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_DIGITS))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX)) "\r\n");
61+
TOTP_CLI_COMMAND_ADD_ARG_DIGITS))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX)) "\r\n");
5062
}
5163

5264
void totp_cli_command_add_docopt_arguments() {
@@ -64,6 +76,10 @@ void totp_cli_command_add_docopt_options() {
6476
TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
6577
DOCOPT_ARGUMENT(
6678
TOTP_CLI_COMMAND_ADD_ARG_DIGITS)) " Number of digits to generate, one of: 6, 8 " DOCOPT_DEFAULT("6") "\r\n");
79+
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
80+
TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX,
81+
DOCOPT_ARGUMENT(
82+
TOTP_CLI_COMMAND_ADD_ARG_DURATION)) " Token lifetime duration in seconds, between: 15 and 255 " DOCOPT_DEFAULT("30") "\r\n");
6783
TOTP_CLI_PRINTF(" " DOCOPT_SWITCH(
6884
TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) " Show console user input as-is without masking\r\n");
6985
}
@@ -110,16 +126,30 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
110126
parsed = true;
111127
}
112128
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX) == 0) {
113-
if(!args_read_string_and_trim(args, temp_str)) {
129+
uint8_t digit_value;
130+
if(!args_read_uint8_and_trim(args, &digit_value)) {
114131
TOTP_CLI_PRINTF(
115-
"Missed value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
132+
"Missed or incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
116133
"\"\r\n");
117-
} else if(!token_info_set_digits_from_int(
118-
token_info, CONVERT_CHAR_TO_DIGIT(furi_string_get_char(temp_str, 0)))) {
134+
} else if(!token_info_set_digits_from_int(token_info, digit_value)) {
119135
TOTP_CLI_PRINTF(
120-
"\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
136+
"\"%" PRIu8 "\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
121137
"\"\r\n",
122-
furi_string_get_cstr(temp_str));
138+
digit_value);
139+
} else {
140+
parsed = true;
141+
}
142+
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX) == 0) {
143+
uint8_t duration_value;
144+
if(!args_read_uint8_and_trim(args, &duration_value)) {
145+
TOTP_CLI_PRINTF(
146+
"Missed or incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX
147+
"\"\r\n");
148+
} else if(!token_info_set_duration_from_int(token_info, duration_value)) {
149+
TOTP_CLI_PRINTF(
150+
"\"%" PRIu8 "\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DURATION_PREFIX
151+
"\"\r\n",
152+
duration_value);
123153
} else {
124154
parsed = true;
125155
}

cli/commands/list/list.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,21 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
4040
return;
4141
}
4242

43-
TOTP_CLI_PRINTF("+-----+-----------------------------+--------+--------+\r\n");
44-
TOTP_CLI_PRINTF("| %-*s | %-*s | %-*s | %-s |\r\n", 3, "#", 27, "Name", 6, "Algo", "Digits");
45-
TOTP_CLI_PRINTF("+-----+-----------------------------+--------+--------+\r\n");
43+
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
44+
TOTP_CLI_PRINTF(
45+
"| %-*s | %-*s | %-*s | %-s | %-s |\r\n", 3, "#", 25, "Name", 6, "Algo", "Ln", "Dur");
46+
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
4647
uint16_t index = 1;
4748
TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
4849
TokenInfo* token_info = (TokenInfo*)node->data;
4950
TOTP_CLI_PRINTF(
50-
"| %-3" PRIu16 " | %-27.27s | %-6s | %-6" PRIu8 " |\r\n",
51+
"| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n",
5152
index,
5253
token_info->name,
5354
get_algo_as_cstr(token_info->algo),
54-
token_info->digits);
55+
token_info->digits,
56+
token_info->duration);
5557
index++;
5658
});
57-
TOTP_CLI_PRINTF("+-----+-----------------------------+--------+--------+\r\n");
59+
TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n");
5860
}

services/config/config.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../../types/common.h"
66
#include "../../types/token_info.h"
77
#include "migrations/config_migration_v1_to_v2.h"
8+
#include "migrations/config_migration_v2_to_v3.h"
89

910
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
1011
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
@@ -173,6 +174,13 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF
173174
flipper_format_write_comment(fff_data_file, temp_str);
174175
flipper_format_write_comment_cstr(fff_data_file, " ");
175176

177+
flipper_format_write_comment_cstr(
178+
fff_data_file,
179+
"# Token lifetime duration in seconds. Should be between 15 and 255. Majority websites requires 30, however some rare websites may require custom lifetime. If you are not sure which one to use - use 30");
180+
furi_string_printf(temp_str, "%s: 30", TOTP_CONFIG_KEY_TOKEN_DURATION);
181+
flipper_format_write_comment(fff_data_file, temp_str);
182+
flipper_format_write_comment_cstr(fff_data_file, " ");
183+
176184
flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE END ===");
177185
flipper_format_write_comment_cstr(fff_data_file, " ");
178186

@@ -232,6 +240,12 @@ TotpConfigFileUpdateResult
232240
break;
233241
}
234242

243+
tmp_uint32 = token_info->duration;
244+
if(!flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DURATION, &tmp_uint32, 1)) {
245+
update_result = TotpConfigFileUpdateError;
246+
break;
247+
}
248+
235249
update_result = TotpConfigFileUpdateSuccess;
236250
} while(false);
237251

@@ -483,6 +497,7 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st
483497
if(file_version == 1) {
484498
if(totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
485499
FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
500+
file_version = 2;
486501
} else {
487502
FURI_LOG_W(
488503
LOGGING_TAG, "An error occurred during migration from v1 to v2");
@@ -491,6 +506,18 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st
491506
}
492507
}
493508

509+
if(file_version == 2) {
510+
if(totp_config_migrate_v2_to_v3(fff_data_file, fff_backup_data_file)) {
511+
FURI_LOG_I(LOGGING_TAG, "Applied migration from v2 to v3");
512+
file_version = 3;
513+
} else {
514+
FURI_LOG_W(
515+
LOGGING_TAG, "An error occurred during migration from v2 to v3");
516+
result = TotpConfigFileOpenError;
517+
break;
518+
}
519+
}
520+
494521
flipper_format_file_close(fff_backup_data_file);
495522
flipper_format_free(fff_backup_data_file);
496523
flipper_format_rewind(fff_data_file);
@@ -669,6 +696,12 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
669696
tokenInfo->digits = TOTP_6_DIGITS;
670697
}
671698

699+
if(!flipper_format_read_uint32(
700+
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, &temp_data32, 1) ||
701+
!token_info_set_duration_from_int(tokenInfo, temp_data32)) {
702+
tokenInfo->duration = TOTP_TOKEN_DURATION_DEFAULT;
703+
}
704+
672705
FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name);
673706

674707
TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);

services/config/constants.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#pragma once
22

33
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
4-
#define CONFIG_FILE_ACTUAL_VERSION 2
4+
#define CONFIG_FILE_ACTUAL_VERSION 3
55

66
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
77
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
88
#define TOTP_CONFIG_KEY_TOKEN_SECRET "TokenSecret"
99
#define TOTP_CONFIG_KEY_TOKEN_ALGO "TokenAlgo"
1010
#define TOTP_CONFIG_KEY_TOKEN_DIGITS "TokenDigits"
11+
#define TOTP_CONFIG_KEY_TOKEN_DURATION "TokenDuration"
1112
#define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
1213
#define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
1314
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"

services/config/migrations/config_migration_v1_to_v2.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "config_migration_v1_to_v2.h"
22
#include <flipper_format/flipper_format.h>
33
#include "../constants.h"
4+
#include "../../../types/token_info.h"
45

56
#define NEW_VERSION 2
67

@@ -36,7 +37,7 @@ bool totp_config_migrate_v1_to_v2(
3637

3738
flipper_format_write_string_cstr(
3839
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
39-
uint32_t default_digits = 6;
40+
const uint32_t default_digits = TOTP_6_DIGITS;
4041
flipper_format_write_uint32(
4142
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
4243
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "config_migration_v2_to_v3.h"
2+
#include <flipper_format/flipper_format.h>
3+
#include "../constants.h"
4+
#include "../../../types/token_info.h"
5+
6+
#define NEW_VERSION 3
7+
8+
bool totp_config_migrate_v2_to_v3(
9+
FlipperFormat* fff_data_file,
10+
FlipperFormat* fff_backup_data_file) {
11+
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION);
12+
13+
FuriString* temp_str = furi_string_alloc();
14+
15+
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
16+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
17+
}
18+
19+
flipper_format_rewind(fff_backup_data_file);
20+
21+
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
22+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
23+
}
24+
25+
flipper_format_rewind(fff_backup_data_file);
26+
27+
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
28+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
29+
}
30+
31+
flipper_format_rewind(fff_backup_data_file);
32+
33+
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_PINSET, temp_str)) {
34+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_PINSET, temp_str);
35+
}
36+
37+
flipper_format_rewind(fff_backup_data_file);
38+
39+
if(flipper_format_read_string(
40+
fff_backup_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str)) {
41+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, temp_str);
42+
}
43+
44+
flipper_format_rewind(fff_backup_data_file);
45+
46+
while(true) {
47+
if(!flipper_format_read_string(
48+
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
49+
break;
50+
}
51+
52+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
53+
54+
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
55+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
56+
57+
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
58+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str);
59+
60+
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
61+
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, temp_str);
62+
63+
const uint32_t default_duration = TOTP_TOKEN_DURATION_DEFAULT;
64+
flipper_format_write_uint32(
65+
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DURATION, &default_duration, 1);
66+
}
67+
68+
furi_string_free(temp_str);
69+
return true;
70+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <flipper_format/flipper_format.h>
4+
5+
bool totp_config_migrate_v2_to_v3(
6+
FlipperFormat* fff_data_file,
7+
FlipperFormat* fff_backup_data_file);

types/token_info.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,12 @@ bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
6161

6262
return false;
6363
}
64+
65+
bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration) {
66+
if(duration >= 15) {
67+
token_info->duration = duration;
68+
return true;
69+
}
70+
71+
return false;
72+
}

types/token_info.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <inttypes.h>
44

5+
#define TOTP_TOKEN_DURATION_DEFAULT 30
6+
57
typedef uint8_t TokenHashAlgo;
68
typedef uint8_t TokenDigitsCount;
79

@@ -70,6 +72,11 @@ typedef struct {
7072
* @brief Desired TOTP token length
7173
*/
7274
TokenDigitsCount digits;
75+
76+
/**
77+
* @brief Desired TOTP token duration in seconds
78+
*/
79+
uint8_t duration;
7380
} TokenInfo;
7481

7582
/**
@@ -102,6 +109,14 @@ bool token_info_set_secret(
102109
* @brief Sets token digits count from \c uint8_t value
103110
* @param token_info instance whichs token digits count length should be updated
104111
* @param digits desired token digits count length
105-
* @return \c true if token digits count length has been updated; \c false p
112+
* @return \c true if token digits count length has been updated; \c false otherwise
106113
*/
107114
bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits);
115+
116+
/**
117+
* @brief Sets token duration from \c uint8_t value
118+
* @param token_info instance whichs token digits count length should be updated
119+
* @param duration desired token duration in seconds
120+
* @return \c true if token duration has been updated; \c false otherwise
121+
*/
122+
bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration);

0 commit comments

Comments
 (0)