Skip to content

Commit 8d4abf9

Browse files
authored
Implemented PIN changing via CLI (#32)
1 parent 4548c3b commit 8d4abf9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+376
-179
lines changed

FAQ.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ For now there is no way to change or recover PIN once it is set without loosing
4444

4545
All token secrets are stored in encrypted form and are tied to an original Flipper device and PIN. Given that, there is no sense to try to backup `/ext/apps/Misc/totp.conf` file as it will not help you in situation when you loose your Flipper device. Instead use your favorite password manager to store plain token secrets and\or any other information which will help you recover your accounts.
4646

47-
## Flipper Authenticator generates invalid tokens, why so?
47+
## Flipper Authenticator generates invalid codes, why so?
4848

49-
There are multiple reasons why Flipper Authenticator generates invalid tokens:
49+
There are multiple reasons why Flipper Authenticator generates invalid codes:
5050

5151
### Clock is not precise
5252

build.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function Get-LatestDirectory {
88

99
$build_commands = @(
1010
[PSCustomObject]@{
11-
Name = "Official Dev";
11+
Name = "Official Dev \ Unleashed";
1212
FbtSwitch = "od";
1313
FirmwarePath = "flipperzero-firmware_official_dev";
1414
ArtifactName = "totp_official-dev_unleashed_fw.fap"

clang-format-all.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$clang_format = Join-Path -Path $PSScriptRoot -ChildPath "flipperzero-firmware_unleashed/toolchain/x86_64-windows/bin/clang-format.exe"
1+
$clang_format = Join-Path -Path $PSScriptRoot -ChildPath "flipperzero-firmware_official_dev/toolchain/x86_64-windows/bin/clang-format.exe"
22
Push-Location $PSScriptRoot
33
Get-ChildItem -Path "totp" -File -Recurse -Include "*.c", "*.h" | ForEach-Object {
44
Write-Host "Formatting $($_.FullName)"

totp/application.fam

+18-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,22 @@ App(
1616
order=20,
1717
fap_category="Misc",
1818
fap_icon_assets="images",
19-
fap_icon="totp_10px.png"
19+
fap_icon="totp_10px.png",
20+
fap_private_libs=[
21+
Lib(
22+
name="base32",
23+
),
24+
Lib(
25+
name="list",
26+
),
27+
Lib(
28+
name="timezone_utils",
29+
),
30+
Lib(
31+
name="polyfills",
32+
),
33+
Lib(
34+
name="roll_value",
35+
),
36+
],
2037
)

totp/services/cli/cli.c totp/cli/cli.c

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "commands/timezone/timezone.h"
1010
#include "commands/help/help.h"
1111
#include "commands/move/move.h"
12+
#include "commands/pin/pin.h"
1213

1314
static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
1415
TOTP_CLI_PRINTF(
@@ -49,6 +50,9 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
4950
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE) == 0 ||
5051
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE_ALT) == 0) {
5152
totp_cli_command_move_handle(plugin_state, args, cli);
53+
} else if(
54+
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_PIN) == 0) {
55+
totp_cli_command_pin_handle(plugin_state, args, cli);
5256
} else {
5357
totp_cli_print_unknown_command(cmd);
5458
}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22

33
#include <cli/cli.h>
4-
#include "../../types/plugin_state.h"
4+
#include "../types/plugin_state.h"
55

66
void totp_cli_register_command_handler(PluginState* plugin_state);
77
void totp_cli_unregister_command_handler();
File renamed without changes.

totp/services/cli/cli_helpers.h totp/cli/cli_helpers.h

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

33
#include <cli/cli.h>
4-
#include "../../types/plugin_state.h"
4+
#include "../types/plugin_state.h"
55

66
#define TOTP_CLI_COMMAND_NAME "totp"
77

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#include "add.h"
22
#include <stdlib.h>
33
#include <lib/toolbox/args.h>
4-
#include "../../../list/list.h"
5-
#include "../../../../types/token_info.h"
6-
#include "../../../config/config.h"
4+
#include "../../../lib/list/list.h"
5+
#include "../../../types/token_info.h"
6+
#include "../../../services/config/config.h"
77
#include "../../cli_helpers.h"
8-
#include "../../../../scenes/scene_director.h"
8+
#include "../../../ui/scene_director.h"
99

1010
#define TOTP_CLI_COMMAND_ADD_ARG_NAME "name"
1111
#define TOTP_CLI_COMMAND_ADD_ARG_ALGO "algo"
@@ -94,7 +94,7 @@ static bool totp_cli_read_secret(Cli* cli, FuriString* out_str, bool mask_user_i
9494
while(cli_read(cli, &c, 1) == 1) {
9595
if(c == CliSymbolAsciiEsc) {
9696
// Some keys generating escape-sequences
97-
// We need to ignore them as we case about alpha-numerics only
97+
// We need to ignore them as we care about alpha-numerics only
9898
uint8_t c2;
9999
cli_read_timeout(cli, &c2, 1, 0);
100100
cli_read_timeout(cli, &c2, 1, 0);

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

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

33
#include <cli/cli.h>
4-
#include "../../../../types/plugin_state.h"
4+
#include "../../../types/plugin_state.h"
55

66
#define TOTP_CLI_COMMAND_ADD "add"
77
#define TOTP_CLI_COMMAND_ADD_ALT "mk"

totp/services/cli/commands/delete/delete.c totp/cli/commands/delete/delete.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
#include <stdlib.h>
44
#include <ctype.h>
55
#include <lib/toolbox/args.h>
6-
#include "../../../list/list.h"
7-
#include "../../../config/config.h"
6+
#include "../../../lib/list/list.h"
7+
#include "../../../services/config/config.h"
88
#include "../../cli_helpers.h"
9-
#include "../../../../scenes/scene_director.h"
9+
#include "../../../ui/scene_director.h"
1010

1111
#define TOTP_CLI_COMMAND_DELETE_ARG_INDEX "index"
1212
#define TOTP_CLI_COMMAND_DELETE_ARG_FORCE_SUFFIX "-f"

totp/services/cli/commands/delete/delete.h totp/cli/commands/delete/delete.h

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

33
#include <cli/cli.h>
4-
#include "../../../../types/plugin_state.h"
4+
#include "../../../types/plugin_state.h"
55

66
#define TOTP_CLI_COMMAND_DELETE "delete"
77
#define TOTP_CLI_COMMAND_DELETE_ALT "rm"

totp/services/cli/commands/help/help.c totp/cli/commands/help/help.c

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../list/list.h"
66
#include "../timezone/timezone.h"
77
#include "../move/move.h"
8+
#include "../pin/pin.h"
89

910
void totp_cli_command_help_docopt_commands() {
1011
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
@@ -25,6 +26,7 @@ void totp_cli_command_help_handle() {
2526
totp_cli_command_delete_docopt_usage();
2627
totp_cli_command_timezone_docopt_usage();
2728
totp_cli_command_move_docopt_usage();
29+
totp_cli_command_pin_docopt_usage();
2830
cli_nl();
2931
TOTP_CLI_PRINTF("Commands:\r\n");
3032
totp_cli_command_help_docopt_commands();
@@ -33,6 +35,7 @@ void totp_cli_command_help_handle() {
3335
totp_cli_command_delete_docopt_commands();
3436
totp_cli_command_timezone_docopt_commands();
3537
totp_cli_command_move_docopt_commands();
38+
totp_cli_command_pin_docopt_commands();
3639
cli_nl();
3740
TOTP_CLI_PRINTF("Arguments:\r\n");
3841
totp_cli_command_add_docopt_arguments();
File renamed without changes.

totp/services/cli/commands/list/list.c totp/cli/commands/list/list.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "list.h"
22
#include <stdlib.h>
3-
#include "../../../list/list.h"
4-
#include "../../../../types/token_info.h"
5-
#include "../../../config/constants.h"
3+
#include "../../../lib/list/list.h"
4+
#include "../../../types/token_info.h"
5+
#include "../../../services/config/constants.h"
66
#include "../../cli_helpers.h"
77

88
static char* get_algo_as_cstr(TokenHashAlgo algo) {

totp/services/cli/commands/list/list.h totp/cli/commands/list/list.h

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

33
#include <cli/cli.h>
4-
#include "../../../../types/plugin_state.h"
4+
#include "../../../types/plugin_state.h"
55

66
#define TOTP_CLI_COMMAND_LIST "list"
77
#define TOTP_CLI_COMMAND_LIST_ALT "ls"

totp/services/cli/commands/move/move.c totp/cli/commands/move/move.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
#include <stdlib.h>
44
#include <lib/toolbox/args.h>
5-
#include "../../../list/list.h"
6-
#include "../../../../types/token_info.h"
7-
#include "../../../config/config.h"
5+
#include "../../../lib/list/list.h"
6+
#include "../../../types/token_info.h"
7+
#include "../../../services/config/config.h"
88
#include "../../cli_helpers.h"
9-
#include "../../../../scenes/scene_director.h"
9+
#include "../../../ui/scene_director.h"
1010

1111
#define TOTP_CLI_COMMAND_MOVE_ARG_INDEX "index"
1212

totp/services/cli/commands/move/move.h totp/cli/commands/move/move.h

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

33
#include <cli/cli.h>
4-
#include "../../../../types/plugin_state.h"
4+
#include "../../../types/plugin_state.h"
55

66
#define TOTP_CLI_COMMAND_MOVE "move"
77
#define TOTP_CLI_COMMAND_MOVE_ALT "mv"

totp/cli/commands/pin/pin.c

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#include "pin.h"
2+
3+
#include <stdlib.h>
4+
#include <lib/toolbox/args.h>
5+
#include "../../../types/token_info.h"
6+
#include "../../../types/user_pin_codes.h"
7+
#include "../../../services/config/config.h"
8+
#include "../../cli_helpers.h"
9+
#include "../../../lib/polyfills/memset_s.h"
10+
#include "../../../services/crypto/crypto.h"
11+
#include "../../../ui/scene_director.h"
12+
13+
#define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set"
14+
#define TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE "remove"
15+
16+
void totp_cli_command_pin_docopt_commands() {
17+
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_PIN " Set\\change\\remove PIN\r\n");
18+
}
19+
20+
void totp_cli_command_pin_docopt_usage() {
21+
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_PIN " " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_PIN_COMMAND_SET " | " TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) "\r\n");
22+
}
23+
24+
static bool totp_cli_read_pin(Cli* cli, uint8_t* pin, uint8_t* pin_length) {
25+
TOTP_CLI_PRINTF("Enter new PIN (use arrow keys on your keyboard): ");
26+
fflush(stdout);
27+
uint8_t c;
28+
*pin_length = 0;
29+
while(cli_read(cli, &c, 1) == 1) {
30+
if(c == CliSymbolAsciiEsc) {
31+
uint8_t c2;
32+
uint8_t c3;
33+
if (cli_read_timeout(cli, &c2, 1, 0) == 1 &&
34+
cli_read_timeout(cli, &c3, 1, 0) == 1 &&
35+
c2 == 0x5b) {
36+
uint8_t code = 0;
37+
switch (c3) {
38+
case 0x44: // left
39+
code = PinCodeArrowLeft;
40+
break;
41+
case 0x41: // up
42+
code = PinCodeArrowUp;
43+
break;
44+
case 0x43: // right
45+
code = PinCodeArrowRight;
46+
break;
47+
case 0x42: // down
48+
code = PinCodeArrowDown;
49+
break;
50+
default:
51+
break;
52+
}
53+
54+
if (code > 0) {
55+
pin[*pin_length] = code;
56+
*pin_length = *pin_length + 1;
57+
putc('*', stdout);
58+
fflush(stdout);
59+
}
60+
}
61+
} else if(c == CliSymbolAsciiETX) {
62+
TOTP_CLI_DELETE_CURRENT_LINE();
63+
TOTP_CLI_PRINTF("Cancelled by user\r\n");
64+
return false;
65+
} else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) {
66+
if (*pin_length > 0) {
67+
*pin_length = *pin_length - 1;
68+
pin[*pin_length] = 0;
69+
TOTP_CLI_DELETE_LAST_CHAR();
70+
}
71+
} else if(c == CliSymbolAsciiCR) {
72+
cli_nl();
73+
break;
74+
}
75+
}
76+
77+
TOTP_CLI_DELETE_LAST_LINE();
78+
return true;
79+
}
80+
81+
void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
82+
UNUSED(plugin_state);
83+
FuriString* temp_str = furi_string_alloc();
84+
85+
bool do_change = false;
86+
bool do_remove = false;
87+
UNUSED(do_remove);
88+
do {
89+
if (!args_read_string_and_trim(args, temp_str)) {
90+
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
91+
break;
92+
}
93+
94+
if (furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_SET) == 0) {
95+
do_change = true;
96+
} else if (furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
97+
do_remove = true;
98+
} else {
99+
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
100+
break;
101+
}
102+
} while (false);
103+
104+
if ((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) {
105+
bool load_generate_token_scene = false;
106+
do {
107+
uint8_t old_iv[TOTP_IV_SIZE];
108+
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
109+
uint8_t new_pin[TOTP_IV_SIZE];
110+
uint8_t new_pin_length = 0;
111+
if (do_change) {
112+
if (!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length) ||
113+
!totp_cli_ensure_authenticated(plugin_state, cli)) {
114+
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
115+
break;
116+
}
117+
} else if (do_remove) {
118+
new_pin_length = 0;
119+
memset(&new_pin[0], 0, TOTP_IV_SIZE);
120+
}
121+
122+
if(plugin_state->current_scene == TotpSceneGenerateToken) {
123+
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
124+
load_generate_token_scene = true;
125+
}
126+
127+
TOTP_CLI_PRINTF("Encrypting, please wait...\r\n");
128+
129+
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
130+
memset(&plugin_state->base_iv[0], 0, TOTP_IV_SIZE);
131+
if (plugin_state->crypto_verify_data != NULL) {
132+
free(plugin_state->crypto_verify_data);
133+
plugin_state->crypto_verify_data = NULL;
134+
}
135+
136+
totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? &new_pin[0] : NULL, new_pin_length);
137+
ListNode* node = plugin_state->tokens_list;
138+
while (node != NULL) {
139+
TokenInfo* token_info = node->data;
140+
size_t plain_token_length;
141+
uint8_t* plain_token = totp_crypto_decrypt(token_info->token, token_info->token_length, &old_iv[0], &plain_token_length);
142+
free(token_info->token);
143+
token_info->token = totp_crypto_encrypt(plain_token, plain_token_length, &plugin_state->iv[0], &token_info->token_length);
144+
memset_s(plain_token, plain_token_length, 0, plain_token_length);
145+
free(plain_token);
146+
node = node->next;
147+
}
148+
149+
totp_full_save_config_file(plugin_state);
150+
151+
TOTP_CLI_DELETE_LAST_LINE();
152+
153+
if (do_change) {
154+
TOTP_CLI_PRINTF("PIN has been successfully changed\r\n");
155+
} else if (do_remove) {
156+
TOTP_CLI_PRINTF("PIN has been successfully removed\r\n");
157+
}
158+
} while (false);
159+
160+
if(load_generate_token_scene) {
161+
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
162+
}
163+
}
164+
165+
furi_string_free(temp_str);
166+
}

totp/cli/commands/pin/pin.h

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include <cli/cli.h>
4+
#include "../../../types/plugin_state.h"
5+
6+
#define TOTP_CLI_COMMAND_PIN "pin"
7+
8+
void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
9+
void totp_cli_command_pin_docopt_commands();
10+
void totp_cli_command_pin_docopt_usage();

0 commit comments

Comments
 (0)