Skip to content

Commit ba70f24

Browse files
committed
* Updated firmware submodules
* Initial implementation of #11
1 parent 0dddcb8 commit ba70f24

21 files changed

+397
-22
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
## Description
1313

1414
Flipper Authenticator is a software-based authenticator that implements two-step verification services using the Time-based One-time Password (TOTP; specified in RFC 6238) and HMAC-based One-time Password algorithm.
15+
1516
It is like [Google Authenticator](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2), but for [Flipper Zero](https://flipperzero.one/) device.
1617

1718
## Support

totp/scenes/authenticate/totp_scene_authenticate.c

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ void totp_scene_authenticate_activate(PluginState* plugin_state) {
2424
scene_state->code_length = 0;
2525
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
2626
plugin_state->current_scene_state = scene_state;
27+
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
2728
}
2829

2930
void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {

totp/scenes/generate_token/totp_scene_generate_token.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void totp_scene_generate_token_activate(
130130
}
131131
}
132132
SceneState* scene_state = malloc(sizeof(SceneState));
133-
if(context == NULL) {
133+
if(context == NULL || context->current_token_index > plugin_state->tokens_count) {
134134
scene_state->current_token_index = 0;
135135
} else {
136136
scene_state->current_token_index = context->current_token_index;

totp/scenes/scene_director.c

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ void totp_scene_director_activate_scene(
2828
case TotpSceneAppSettings:
2929
totp_scene_app_settings_activate(plugin_state, context);
3030
break;
31+
case TotpSceneNone:
32+
break;
3133
}
3234

3335
plugin_state->current_scene = scene;
@@ -51,6 +53,8 @@ void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state
5153
case TotpSceneAppSettings:
5254
totp_scene_app_settings_deactivate(plugin_state);
5355
break;
56+
case TotpSceneNone:
57+
break;
5458
}
5559
}
5660

@@ -79,6 +83,8 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_
7983
case TotpSceneAppSettings:
8084
totp_scene_app_settings_render(canvas, plugin_state);
8185
break;
86+
case TotpSceneNone:
87+
break;
8288
}
8389
}
8490

@@ -108,6 +114,8 @@ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* con
108114
case TotpSceneAppSettings:
109115
processing = totp_scene_app_settings_handle_event(event, plugin_state);
110116
break;
117+
case TotpSceneNone:
118+
break;
111119
}
112120

113121
return processing;

totp/scenes/token_menu/totp_scene_token_menu.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,7 @@ bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* p
139139
dialog_message_show(plugin_state->dialogs, message);
140140
dialog_message_free(message);
141141
if(dialog_result == DialogMessageButtonRight) {
142-
uint8_t i = 0;
143-
144-
ListNode* list_node = plugin_state->tokens_list;
145-
while(i < scene_state->current_token_index && list_node->next != NULL) {
146-
list_node = list_node->next;
147-
i++;
148-
}
142+
ListNode* list_node = list_element_at(plugin_state->tokens_list, scene_state->current_token_index);
149143

150144
TokenInfo* tokenInfo = list_node->data;
151145
token_info_free(tokenInfo);

totp/scenes/totp_scenes_enum.h

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
typedef enum {
4+
TotpSceneNone,
45
TotpSceneAuthentication,
56
TotpSceneGenerateToken,
67
TotpSceneAddNewToken,

totp/services/cli/cli.c

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Original idea: https://github.com/br0ziliy
2+
3+
#include "cli.h"
4+
#include <lib/toolbox/args.h>
5+
#include "commands/list/list.h"
6+
#include "commands/add/add.h"
7+
#include "commands/delete/delete.h"
8+
9+
#define TOTP_CLI_COMMAND_NAME "totp"
10+
11+
static void totp_cli_print_unknown_command(FuriString* unknown_command) {
12+
printf("Command \"%s\" is unknown. Use \"help\" command to get list of available commands.", furi_string_get_cstr(unknown_command));
13+
}
14+
15+
static void totp_cli_print_help() {
16+
printf("Usage:\r\n");
17+
printf("totp <command> <arguments>\r\n");
18+
printf("Command list:\r\n");
19+
printf("\thelp - print command usage help\r\n");
20+
printf("\tlist - list all tokens\r\n");
21+
printf("\tdelete <INDEX> [-f] - delete token\r\n");
22+
printf("\t\t<INDEX> - token index in the list\r\n");
23+
printf("\t\t-f - [OPTIONAL] force command to do not ask user for interactive confirmation\r\n");
24+
printf("\tadd <NAME> <SECRET> [-a <ALGO>] [-d <DIGITS>] - add new token\r\n");
25+
printf("\t\t<NAME> - token name\r\n");
26+
printf("\t\t<SECRET> - Base32 token secret\r\n");
27+
printf("\t\t<ALGO> - [OPTIONAL] token hashing algorithm, could be one of: sha1, sha256, sha512; default: sha1\r\n");
28+
printf("\t\t<DIGITS> - [OPTIONAL] number of digits to generate, one of: 6, 8; default: 6\r\n\r\n");
29+
}
30+
31+
static void totp_cli_print_unauthenticated() {
32+
printf("Pleases enter PIN on your flipper device\r\n");
33+
}
34+
35+
static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
36+
PluginState* plugin_state = (PluginState* )context;
37+
38+
if (plugin_state->current_scene == TotpSceneAuthentication) {
39+
totp_cli_print_unauthenticated();
40+
41+
while (plugin_state->current_scene == TotpSceneAuthentication && !cli_cmd_interrupt_received(cli)) {
42+
furi_delay_tick(0);
43+
}
44+
45+
if (plugin_state->current_scene == TotpSceneAuthentication) {
46+
return;
47+
}
48+
}
49+
50+
FuriString* cmd = furi_string_alloc();
51+
52+
args_read_string_and_trim(args, cmd);
53+
54+
if(furi_string_cmp_str(cmd, "help") == 0 || furi_string_empty(cmd)) {
55+
totp_cli_print_help();
56+
} else if(furi_string_cmp_str(cmd, "add") == 0) {
57+
totp_cli_handle_add_command(plugin_state, args);
58+
} else if(furi_string_cmp_str(cmd, "list") == 0) {
59+
totp_cli_handle_list_command(plugin_state);
60+
} else if(furi_string_cmp_str(cmd, "delete") == 0) {
61+
totp_cli_handle_delete_command(plugin_state, args, cli);
62+
} else {
63+
totp_cli_print_unknown_command(cmd);
64+
}
65+
66+
furi_string_free(cmd);
67+
}
68+
69+
void totp_cli_register_command_handler(PluginState* plugin_state) {
70+
Cli* cli = furi_record_open(RECORD_CLI);
71+
cli_add_command(cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, plugin_state);
72+
furi_record_close(RECORD_CLI);
73+
}
74+
75+
void totp_cli_unregister_command_handler() {
76+
Cli* cli = furi_record_open(RECORD_CLI);
77+
cli_delete_command(cli, TOTP_CLI_COMMAND_NAME);
78+
furi_record_close(RECORD_CLI);
79+
}

totp/services/cli/cli.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <cli/cli.h>
4+
#include "../../types/plugin_state.h"
5+
6+
void totp_cli_register_command_handler(PluginState* plugin_state);
7+
void totp_cli_unregister_command_handler();
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "cli_common_helpers.h"
2+
#include <cli/cli.h>
3+
4+
void totp_cli_print_invalid_arguments() {
5+
printf("Invalid command arguments. use \"help\" command to get list of available commands");
6+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
void totp_cli_print_invalid_arguments();

totp/services/cli/commands/add/add.c

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "add.h"
2+
#include <stdlib.h>
3+
#include <lib/toolbox/args.h>
4+
#include "../../../list/list.h"
5+
#include "../../../../types/token_info.h"
6+
#include "../../../config/config.h"
7+
#include "../../cli_common_helpers.h"
8+
#include "../../../../scenes/scene_director.h"
9+
10+
static bool token_info_set_digits_from_str(TokenInfo* token_info, FuriString* str) {
11+
switch(furi_string_get_char(str, 0)) {
12+
case '6':
13+
token_info->digits = TOTP_6_DIGITS;
14+
return true;
15+
case '8':
16+
token_info->digits = TOTP_8_DIGITS;
17+
return true;
18+
}
19+
20+
return false;
21+
}
22+
23+
static bool token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) {
24+
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
25+
token_info->algo = SHA1;
26+
return true;
27+
}
28+
29+
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME) == 0) {
30+
token_info->algo = SHA256;
31+
return true;
32+
}
33+
34+
if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME) == 0) {
35+
token_info->algo = SHA512;
36+
return true;
37+
}
38+
39+
return false;
40+
}
41+
42+
void totp_cli_handle_add_command(PluginState* plugin_state, FuriString* args) {
43+
FuriString* temp_str = furi_string_alloc();
44+
const char* temp_cstr;
45+
46+
TokenInfo* token_info = token_info_alloc();
47+
48+
// Reading token name
49+
if (!args_read_probably_quoted_string_and_trim(args, temp_str)) {
50+
totp_cli_print_invalid_arguments();
51+
furi_string_free(temp_str);
52+
token_info_free(token_info);
53+
return;
54+
}
55+
56+
temp_cstr = furi_string_get_cstr(temp_str);
57+
token_info->name = malloc(strlen(temp_cstr) + 1);
58+
strcpy(token_info->name, temp_cstr);
59+
60+
// Reading token secret
61+
if (!args_read_probably_quoted_string_and_trim(args, temp_str)) {
62+
totp_cli_print_invalid_arguments();
63+
furi_string_free(temp_str);
64+
token_info_free(token_info);
65+
return;
66+
}
67+
68+
temp_cstr = furi_string_get_cstr(temp_str);
69+
if (!token_info_set_secret(token_info, temp_cstr, strlen(temp_cstr), plugin_state->iv)) {
70+
printf("Token secret seems to be invalid and can not be parsed\r\n");
71+
furi_string_free(temp_str);
72+
token_info_free(token_info);
73+
return;
74+
}
75+
76+
// Read optional arguments
77+
while (args_read_string_and_trim(args, temp_str)) {
78+
bool parsed = false;
79+
if (furi_string_cmpi_str(temp_str, "-a") == 0) {
80+
if (!args_read_string_and_trim(args, temp_str)) {
81+
printf("Missed value for argument \"-a\"\r\n");
82+
} else if (!token_info_set_algo_from_str(token_info, temp_str)) {
83+
printf("\"%s\" is incorrect value for argument \"-a\"\r\n", furi_string_get_cstr(temp_str));
84+
} else {
85+
parsed = true;
86+
}
87+
} else if (furi_string_cmpi_str(temp_str, "-d") == 0) {
88+
if (!args_read_string_and_trim(args, temp_str)) {
89+
printf("Missed value for argument \"-d\"\r\n");
90+
} else if (!token_info_set_digits_from_str(token_info, temp_str)) {
91+
printf("\"%s\" is incorrect value for argument \"-d\"\r\n", furi_string_get_cstr(temp_str));
92+
} else {
93+
parsed = true;
94+
}
95+
}
96+
if (!parsed) {
97+
totp_cli_print_invalid_arguments();
98+
furi_string_free(temp_str);
99+
token_info_free(token_info);
100+
return;
101+
}
102+
}
103+
104+
bool load_generate_token_scene = false;
105+
if (plugin_state->current_scene == TotpSceneGenerateToken) {
106+
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
107+
load_generate_token_scene = true;
108+
}
109+
110+
if(plugin_state->tokens_list == NULL) {
111+
plugin_state->tokens_list = list_init_head(token_info);
112+
} else {
113+
list_add(plugin_state->tokens_list, token_info);
114+
}
115+
plugin_state->tokens_count++;
116+
totp_config_file_save_new_token(token_info);
117+
118+
if (load_generate_token_scene) {
119+
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
120+
}
121+
122+
furi_string_free(temp_str);
123+
124+
printf("Token \"%s\" has been successfully added\r\n", token_info->name);
125+
}

totp/services/cli/commands/add/add.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
#include <cli/cli.h>
4+
#include "../../../../types/plugin_state.h"
5+
6+
void totp_cli_handle_add_command(PluginState* plugin_state, FuriString* args);

0 commit comments

Comments
 (0)