mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-04 22:33:36 -07:00
totp
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 99
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: c++03
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="Authenticator",
|
||||
appid="totp",
|
||||
name="Authenticator",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="totp_app",
|
||||
|
||||
@@ -101,7 +101,7 @@ bool totp_scene_app_settings_handle_event(
|
||||
}
|
||||
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
if(event->input.type != InputTypePress) {
|
||||
if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "totp_scene_authenticate.h"
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <Authenticator_icons.h>
|
||||
#include <totp_icons.h>
|
||||
#include "../../types/common.h"
|
||||
#include "../../services/ui/constants.h"
|
||||
#include "../../services/config/config.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <Authenticator_icons.h>
|
||||
#include <totp_icons.h>
|
||||
#include "totp_scene_generate_token.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../../types/common.h"
|
||||
@@ -293,7 +293,7 @@ bool totp_scene_generate_token_handle_event(
|
||||
return true;
|
||||
}
|
||||
|
||||
if(event->input.type != InputTypePress) {
|
||||
if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,46 @@
|
||||
#include "../types/plugin_event.h"
|
||||
#include "totp_scenes_enum.h"
|
||||
|
||||
/**
|
||||
* @brief Activates scene
|
||||
* @param plugin_state application state
|
||||
* @param scene scene to be activated
|
||||
* @param context scene context to be passed to the scene activation method
|
||||
*/
|
||||
void totp_scene_director_activate_scene(
|
||||
PluginState* const plugin_state,
|
||||
Scene scene,
|
||||
const void* context);
|
||||
|
||||
/**
|
||||
* @brief Deactivate current scene
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Initializes all the available scenes
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_init_scenes(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Renders current scene
|
||||
* @param canvas canvas to render at
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Disposes all the available scenes
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_dispose(const PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Handles application event for the current scene
|
||||
* @param event event to be handled
|
||||
* @param plugin_state application state
|
||||
* @return \c true if event handled and applilcation should continue; \c false if application should be closed
|
||||
*/
|
||||
bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state);
|
||||
|
||||
@@ -147,13 +147,14 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
|
||||
dialog_message_free(message);
|
||||
if(dialog_result == DialogMessageButtonRight &&
|
||||
!scene_state->current_token_index.is_null) {
|
||||
ListNode* list_node = list_element_at(
|
||||
plugin_state->tokens_list, scene_state->current_token_index.value);
|
||||
|
||||
TokenInfo* tokenInfo = list_node->data;
|
||||
token_info_free(tokenInfo);
|
||||
plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node);
|
||||
TokenInfo* tokenInfo = NULL;
|
||||
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);
|
||||
|
||||
totp_full_save_config_file(plugin_state);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
|
||||
@@ -1,10 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief TOTP application scenes
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief Empty scene which does nothing
|
||||
*/
|
||||
TotpSceneNone,
|
||||
|
||||
/**
|
||||
* @brief Scene where user have to enter PIN to authenticate
|
||||
*/
|
||||
TotpSceneAuthentication,
|
||||
|
||||
/**
|
||||
* @brief Scene where actual TOTP token is getting generated and displayed to the user
|
||||
*/
|
||||
TotpSceneGenerateToken,
|
||||
|
||||
/**
|
||||
* @brief Scene where user can add new token
|
||||
*/
|
||||
TotpSceneAddNewToken,
|
||||
|
||||
/**
|
||||
* @brief Scene with a menu for given token, allowing user to do multiple actions
|
||||
*/
|
||||
TotpSceneTokenMenu,
|
||||
|
||||
/**
|
||||
* @brief Scene where user can change application settings
|
||||
*/
|
||||
TotpSceneAppSettings
|
||||
} Scene;
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "base32.h"
|
||||
|
||||
int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) {
|
||||
|
||||
@@ -29,5 +29,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize)
|
||||
__attribute__((visibility("hidden")));
|
||||
/**
|
||||
* @brief Decodes Base-32 encoded bytes into plain bytes.
|
||||
* @param encoded Base-32 encoded bytes
|
||||
* @param[out] result result output buffer
|
||||
* @param bufSize result output buffer size
|
||||
* @return Decoded result length in bytes if successfully decoded; \c -1 otherwise
|
||||
*/
|
||||
int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "commands/delete/delete.h"
|
||||
#include "commands/timezone/timezone.h"
|
||||
#include "commands/help/help.h"
|
||||
#include "commands/move/move.h"
|
||||
|
||||
static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
|
||||
TOTP_CLI_PRINTF(
|
||||
@@ -44,6 +45,10 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_TIMEZONE) == 0 ||
|
||||
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_TIMEZONE_ALT) == 0) {
|
||||
totp_cli_command_timezone_handle(plugin_state, args, cli);
|
||||
} else if(
|
||||
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE) == 0 ||
|
||||
furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE_ALT) == 0) {
|
||||
totp_cli_command_move_handle(plugin_state, args, cli);
|
||||
} else {
|
||||
totp_cli_print_unknown_command(cmd);
|
||||
}
|
||||
|
||||
@@ -175,6 +175,8 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
|
||||
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) == 0) {
|
||||
mask_user_input = false;
|
||||
parsed = true;
|
||||
} else {
|
||||
TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../delete/delete.h"
|
||||
#include "../list/list.h"
|
||||
#include "../timezone/timezone.h"
|
||||
#include "../move/move.h"
|
||||
|
||||
void totp_cli_command_help_docopt_commands() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
|
||||
@@ -23,6 +24,7 @@ void totp_cli_command_help_handle() {
|
||||
totp_cli_command_add_docopt_usage();
|
||||
totp_cli_command_delete_docopt_usage();
|
||||
totp_cli_command_timezone_docopt_usage();
|
||||
totp_cli_command_move_docopt_usage();
|
||||
cli_nl();
|
||||
TOTP_CLI_PRINTF("Commands:\r\n");
|
||||
totp_cli_command_help_docopt_commands();
|
||||
@@ -30,6 +32,7 @@ void totp_cli_command_help_handle() {
|
||||
totp_cli_command_add_docopt_commands();
|
||||
totp_cli_command_delete_docopt_commands();
|
||||
totp_cli_command_timezone_docopt_commands();
|
||||
totp_cli_command_move_docopt_commands();
|
||||
cli_nl();
|
||||
TOTP_CLI_PRINTF("Arguments:\r\n");
|
||||
totp_cli_command_add_docopt_arguments();
|
||||
@@ -39,4 +42,5 @@ void totp_cli_command_help_handle() {
|
||||
TOTP_CLI_PRINTF("Options:\r\n");
|
||||
totp_cli_command_add_docopt_options();
|
||||
totp_cli_command_delete_docopt_options();
|
||||
totp_cli_command_move_docopt_options();
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
#include "move.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include "../../../list/list.h"
|
||||
#include "../../../../types/token_info.h"
|
||||
#include "../../../config/config.h"
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../../../scenes/scene_director.h"
|
||||
|
||||
#define TOTP_CLI_COMMAND_MOVE_ARG_INDEX "index"
|
||||
|
||||
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME "name"
|
||||
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX "-n"
|
||||
|
||||
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX "index"
|
||||
#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX "-i"
|
||||
|
||||
void totp_cli_command_move_docopt_commands() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_MOVE ", " TOTP_CLI_COMMAND_MOVE_ALT
|
||||
" Move\\rename token\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_move_docopt_usage() {
|
||||
TOTP_CLI_PRINTF(
|
||||
" " TOTP_CLI_COMMAND_NAME
|
||||
" " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_MOVE " | " TOTP_CLI_COMMAND_MOVE_ALT) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_INDEX) " " DOCOPT_OPTIONAL(
|
||||
DOCOPT_OPTION(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX,
|
||||
DOCOPT_ARGUMENT(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX))) "\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_move_docopt_options() {
|
||||
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX,
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name.\r\n");
|
||||
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX,
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index.\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||
int token_index;
|
||||
if(!args_read_int_and_trim(args, &token_index)) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(token_index < 1 || token_index > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
return;
|
||||
}
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
char* new_token_name = NULL;
|
||||
int new_token_index = 0;
|
||||
|
||||
while(args_read_string_and_trim(args, temp_str)) {
|
||||
bool parsed = false;
|
||||
if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX) == 0) {
|
||||
if(!args_read_string_and_trim(args, temp_str)) {
|
||||
TOTP_CLI_PRINTF(
|
||||
"Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX
|
||||
"\"\r\n");
|
||||
} else {
|
||||
if(new_token_name != NULL) {
|
||||
free(new_token_name);
|
||||
}
|
||||
|
||||
new_token_name = malloc(furi_string_size(temp_str) + 1);
|
||||
if(new_token_name == NULL) {
|
||||
furi_string_free(temp_str);
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(
|
||||
new_token_name,
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str) + 1);
|
||||
parsed = true;
|
||||
}
|
||||
} else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX) == 0) {
|
||||
if(!args_read_int_and_trim(args, &new_token_index)) {
|
||||
TOTP_CLI_PRINTF(
|
||||
"Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX
|
||||
"\"\r\n");
|
||||
} else if(new_token_index < 1 || new_token_index > plugin_state->tokens_count) {
|
||||
TOTP_CLI_PRINTF(
|
||||
"\"%" PRId16
|
||||
"\" is incorrect value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX
|
||||
"\"\r\n",
|
||||
new_token_index);
|
||||
} else {
|
||||
parsed = true;
|
||||
}
|
||||
} else {
|
||||
TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
furi_string_free(temp_str);
|
||||
if(new_token_name != NULL) {
|
||||
free(new_token_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
|
||||
furi_string_free(temp_str);
|
||||
if(new_token_name != NULL) {
|
||||
free(new_token_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool token_updated = false;
|
||||
TokenInfo* token_info = NULL;
|
||||
if(new_token_index > 0) {
|
||||
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);
|
||||
token_updated = true;
|
||||
} else {
|
||||
token_info = list_element_at(plugin_state->tokens_list, token_index - 1)->data;
|
||||
}
|
||||
|
||||
if(new_token_name != NULL) {
|
||||
free(token_info->name);
|
||||
token_info->name = new_token_name;
|
||||
token_updated = true;
|
||||
}
|
||||
|
||||
if(token_updated) {
|
||||
totp_full_save_config_file(plugin_state);
|
||||
}
|
||||
|
||||
if(activate_generate_token_scene) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
|
||||
if(token_updated) {
|
||||
TOTP_CLI_PRINTF("Token \"%s\" has been successfully updated\r\n", token_info->name);
|
||||
} else {
|
||||
TOTP_CLI_PRINT_INVALID_ARGUMENTS();
|
||||
}
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cli/cli.h>
|
||||
#include "../../../../types/plugin_state.h"
|
||||
|
||||
#define TOTP_CLI_COMMAND_MOVE "move"
|
||||
#define TOTP_CLI_COMMAND_MOVE_ALT "mv"
|
||||
|
||||
void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
|
||||
void totp_cli_command_move_docopt_commands();
|
||||
void totp_cli_command_move_docopt_usage();
|
||||
void totp_cli_command_move_docopt_options();
|
||||
@@ -6,18 +6,77 @@
|
||||
#include "../../types/token_info.h"
|
||||
#include "constants.h"
|
||||
|
||||
/**
|
||||
* @brief Token loading results
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @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
|
||||
} TokenLoadingResult;
|
||||
|
||||
/**
|
||||
* @brief Opens storage record
|
||||
* @return Storage record
|
||||
*/
|
||||
Storage* totp_open_storage();
|
||||
|
||||
/**
|
||||
* @brief Closes storage record
|
||||
*/
|
||||
void totp_close_storage();
|
||||
|
||||
/**
|
||||
* @brief Opens or creates TOTP application standard config file
|
||||
* @param storage storage record to use
|
||||
* @return Config file reference
|
||||
*/
|
||||
FlipperFormat* totp_open_config_file(Storage* storage);
|
||||
|
||||
/**
|
||||
* @brief Closes config file
|
||||
* @param file config file reference
|
||||
*/
|
||||
void totp_close_config_file(FlipperFormat* file);
|
||||
|
||||
/**
|
||||
* @brief Saves all the settings and tokens to an application config file
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void 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
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_config_file_load_base(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
|
||||
*/
|
||||
void totp_config_file_save_new_token(const TokenInfo* token_info);
|
||||
|
||||
/**
|
||||
* @brief Updates timezone offset in an application config file
|
||||
* @param new_timezone_offset new timezone offset to be set
|
||||
*/
|
||||
void totp_config_file_update_timezone_offset(float new_timezone_offset);
|
||||
|
||||
@@ -2,15 +2,45 @@
|
||||
|
||||
#include "../../types/plugin_state.h"
|
||||
|
||||
/**
|
||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||
* @param plain_data plain data to be encrypted
|
||||
* @param plain_data_length plain data length
|
||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
||||
* @param[out] encrypted_data_length encrypted data length
|
||||
* @return Encrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_encrypt(
|
||||
const uint8_t* plain_data,
|
||||
const size_t plain_data_length,
|
||||
const uint8_t* iv,
|
||||
size_t* encrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||
* @param encrypted_data encrypted data to be decrypted
|
||||
* @param encrypted_data_length encrypted data length
|
||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
||||
* @param[out] decrypted_data_length decrypted data length
|
||||
* @return Decrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_decrypt(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const uint8_t* iv,
|
||||
size_t* decrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Seed initialization vector (IV) using user's PIN
|
||||
* @param plugin_state application state
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
*/
|
||||
void 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
|
||||
* @param plugin_state application state
|
||||
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||
*/
|
||||
bool totp_crypto_verify_key(const PluginState* plugin_state);
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _RSIZE_T_DECLARED
|
||||
typedef uint64_t rsize_t;
|
||||
@@ -13,4 +12,12 @@ typedef int16_t errno_t; //-V677
|
||||
#define _ERRNOT_DECLARED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Copies the value \p c into each of the first \p n characters of the object pointed to by \p s.
|
||||
* @param s pointer to the object to fill
|
||||
* @param smax size of the destination object
|
||||
* @param c fill byte
|
||||
* @param n number of bytes to fill
|
||||
* @return \c 0 on success; non-zero otherwise
|
||||
*/
|
||||
errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n);
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "hid_worker.h"
|
||||
|
||||
const uint8_t hid_number_keys[10] = {
|
||||
static const uint8_t hid_number_keys[10] = {
|
||||
HID_KEYBOARD_0,
|
||||
HID_KEYBOARD_1,
|
||||
HID_KEYBOARD_2,
|
||||
@@ -19,6 +19,10 @@ static void totp_hid_worker_restore_usb_mode(TotpHidWorkerTypeContext* context)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool totp_hid_worker_stop_requested() {
|
||||
return furi_thread_flags_get() & TotpHidWorkerEvtStop;
|
||||
}
|
||||
|
||||
static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) {
|
||||
context->usb_mode_prev = furi_hal_usb_get_config();
|
||||
furi_hal_usb_unlock();
|
||||
@@ -27,11 +31,11 @@ static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) {
|
||||
do {
|
||||
furi_delay_ms(500);
|
||||
i++;
|
||||
} while(!furi_hal_hid_is_connected() && i < 50);
|
||||
furi_delay_ms(500);
|
||||
} while(!furi_hal_hid_is_connected() && i < 100 && !totp_hid_worker_stop_requested());
|
||||
|
||||
if(furi_hal_hid_is_connected() &&
|
||||
furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
|
||||
furi_delay_ms(500);
|
||||
i = 0;
|
||||
while(i < context->string_length && context->string[i] != 0) {
|
||||
uint8_t digit = context->string[i] - '0';
|
||||
@@ -91,7 +95,7 @@ TotpHidWorkerTypeContext* totp_hid_worker_start() {
|
||||
}
|
||||
|
||||
void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), TotpHidWorkerEvtStop);
|
||||
furi_thread_join(context->thread);
|
||||
furi_thread_free(context->thread);
|
||||
@@ -101,6 +105,6 @@ void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) {
|
||||
}
|
||||
|
||||
void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event) {
|
||||
furi_assert(context);
|
||||
furi_assert(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
|
||||
}
|
||||
@@ -2,5 +2,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Swap bytes in 32-bit value
|
||||
* @param val value to swap bytes in
|
||||
* @return Value with bytes swapped
|
||||
*/
|
||||
uint32_t swap_uint32(uint32_t val);
|
||||
|
||||
/**
|
||||
* @brief Swap bytes in 64-bit value
|
||||
* @param val value to swap bytes in
|
||||
* @return Value with bytes swapped
|
||||
*/
|
||||
uint64_t swap_uint64(uint64_t val);
|
||||
|
||||
@@ -29,7 +29,7 @@ ListNode* list_add(ListNode* head, void* data) {
|
||||
}
|
||||
|
||||
ListNode* list_find(ListNode* head, const void* data) {
|
||||
ListNode* it;
|
||||
ListNode* it = NULL;
|
||||
|
||||
for(it = head; it != NULL; it = it->next)
|
||||
if(it->data == data) break;
|
||||
@@ -67,6 +67,63 @@ ListNode* list_remove(ListNode* head, ListNode* 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;
|
||||
|
||||
@@ -3,25 +3,85 @@
|
||||
#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. */
|
||||
ListNode* list_find(
|
||||
ListNode* head,
|
||||
const void* data); /* returns pointer of element with specified data in list. */
|
||||
ListNode* list_element_at(
|
||||
ListNode* head,
|
||||
uint16_t index); /* returns pointer of element with specified index in list. */
|
||||
ListNode* list_remove(
|
||||
ListNode* head,
|
||||
ListNode* ep); /* removes element from the list and returns new head node. */
|
||||
void list_free(ListNode* head); /* deletes all elements of the list. */
|
||||
|
||||
/**
|
||||
* @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) \
|
||||
do { \
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum { RollOverflowBehaviorStop, RollOverflowBehaviorRoll } TotpRollValueOverflowBehavior;
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief Do not change value if it reached constraint
|
||||
*/
|
||||
RollOverflowBehaviorStop,
|
||||
|
||||
/**
|
||||
* @brief Set value to opposite constraint value if it reached constraint
|
||||
*/
|
||||
RollOverflowBehaviorRoll
|
||||
} TotpRollValueOverflowBehavior;
|
||||
|
||||
#define TOTP_ROLL_VALUE_FN_HEADER(type, step_type) \
|
||||
void totp_roll_value_##type( \
|
||||
@@ -12,6 +22,35 @@ typedef enum { RollOverflowBehaviorStop, RollOverflowBehaviorRoll } TotpRollValu
|
||||
type max, \
|
||||
TotpRollValueOverflowBehavior overflow_behavior)
|
||||
|
||||
/**
|
||||
* @brief Rolls \c int8_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.
|
||||
* @param[in,out] value value to roll
|
||||
* @param step step to be used to change value
|
||||
* @param min minimal possible value
|
||||
* @param max maximum possible value
|
||||
* @param overflow_behavior defines what to do when value reaches constraint value
|
||||
*/
|
||||
TOTP_ROLL_VALUE_FN_HEADER(int8_t, int8_t);
|
||||
|
||||
/**
|
||||
* @brief Rolls \c uint8_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.
|
||||
* @param[in,out] value value to roll
|
||||
* @param step step to be used to change value
|
||||
* @param min minimal possible value
|
||||
* @param max maximum possible value
|
||||
* @param overflow_behavior defines what to do when value reaches constraint value
|
||||
*/
|
||||
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.
|
||||
* When value reaches constraint value \p overflow_behavior defines what to do next.
|
||||
* @param[in,out] value value to roll
|
||||
* @param step step to be used to change value
|
||||
* @param min minimal possible value
|
||||
* @param max maximum possible value
|
||||
* @param overflow_behavior defines what to do when value reaches constraint value
|
||||
*/
|
||||
TOTP_ROLL_VALUE_FN_HEADER(uint16_t, int16_t);
|
||||
@@ -2,5 +2,17 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @brief Calculates timezone offset in seconds given timezone offset in hours.
|
||||
* @param hours timezone offset in hours
|
||||
* @return Timezone offset in seconds.
|
||||
*/
|
||||
int32_t timezone_offset_from_hours(float hours);
|
||||
|
||||
/**
|
||||
* @brief Applies timezone offset to a given time.
|
||||
* @param time time to apply offset to.
|
||||
* @param offset timezone offset in seconds.
|
||||
* @return Time with timezone offset applied.
|
||||
*/
|
||||
uint64_t timezone_offset_apply(uint64_t time, int32_t offset);
|
||||
|
||||
@@ -11,48 +11,43 @@
|
||||
#include "../hmac/byteswap.h"
|
||||
#include "../timezone_utils/timezone_utils.h"
|
||||
|
||||
/*
|
||||
Generates the timeblock for a time in seconds.
|
||||
|
||||
Timeblocks are the amount of intervals in a given time. For example,
|
||||
if 1,000,000 seconds has passed for 30 second intervals, you would get
|
||||
33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
|
||||
|
||||
for_time is a time in seconds to get the current timeblocks
|
||||
|
||||
Returns
|
||||
timeblock given for_time, using data->interval
|
||||
error, 0
|
||||
*/
|
||||
#define HMAC_MAX_SIZE 64
|
||||
|
||||
/**
|
||||
* @brief Generates the timeblock for a time in seconds.
|
||||
* Timeblocks are the amount of intervals in a given time. For example,
|
||||
* if 1,000,000 seconds has passed for 30 second intervals, you would get
|
||||
* 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
|
||||
* @param interval in seconds
|
||||
* @param for_time a time in seconds to get the current timeblocks
|
||||
* @return Timeblock given \p for_time using \p interval
|
||||
*/
|
||||
uint64_t totp_timecode(uint8_t interval, uint64_t for_time) {
|
||||
return for_time / interval;
|
||||
}
|
||||
|
||||
/*
|
||||
Generates an OTP (One Time Password).
|
||||
|
||||
input is a number used to generate the OTP
|
||||
out_str is the null-terminated output string already allocated
|
||||
|
||||
Returns
|
||||
OTP code if otp code was successfully generated
|
||||
0 otherwise
|
||||
*/
|
||||
/**
|
||||
* @brief Generates an OTP (One Time Password)
|
||||
* @param algo hashing algorithm to be used
|
||||
* @param digits desired TOTP code length
|
||||
* @param plain_secret plain token secret
|
||||
* @param plain_secret_length plain token secret length
|
||||
* @param input input data for OTP code generation
|
||||
* @return OTP code if code was successfully generated; 0 otherwise
|
||||
*/
|
||||
uint32_t otp_generate(
|
||||
TOTP_ALGO algo,
|
||||
uint8_t digits,
|
||||
const uint8_t* plain_secret,
|
||||
size_t plain_secret_length,
|
||||
uint64_t input) {
|
||||
uint8_t* hmac = malloc(64);
|
||||
if(hmac == NULL) return OTP_ERROR;
|
||||
memset(hmac, 0, 64);
|
||||
uint8_t hmac[HMAC_MAX_SIZE] = {0};
|
||||
|
||||
uint64_t input_swapped = swap_uint64(input);
|
||||
|
||||
int hmac_len = (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, hmac);
|
||||
int hmac_len =
|
||||
(*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, &hmac[0]);
|
||||
if(hmac_len == 0) {
|
||||
free(hmac);
|
||||
return OTP_ERROR;
|
||||
}
|
||||
|
||||
@@ -62,21 +57,9 @@ uint32_t otp_generate(
|
||||
(hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
|
||||
i_code %= (uint64_t)pow(10, digits);
|
||||
|
||||
free(hmac);
|
||||
return i_code;
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a OTP key using the totp algorithm.
|
||||
|
||||
for_time is the time the generated key will be created for
|
||||
offset is a timeblock adjustment for the generated key
|
||||
out_str is the null-terminated output string already allocated
|
||||
|
||||
Returns
|
||||
TOTP code if otp code was successfully generated
|
||||
0 otherwise
|
||||
*/
|
||||
uint32_t totp_at(
|
||||
TOTP_ALGO algo,
|
||||
uint8_t digits,
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
|
||||
#define OTP_ERROR (0)
|
||||
|
||||
/*
|
||||
Must compute HMAC using passed arguments,
|
||||
output as char array through output.
|
||||
|
||||
key is secret key.
|
||||
input is input number.
|
||||
output is an output buffer of the resulting HMAC operation.
|
||||
|
||||
Must return 0 if error, or the length in bytes of the HMAC operation.
|
||||
*/
|
||||
/**
|
||||
* @brief Must compute HMAC using passed arguments, output as char array through output.
|
||||
* \p key is secret key buffer.
|
||||
* \p key_length is secret key buffer length.
|
||||
* \p input is input buffer.
|
||||
* \p input_length is input buffer length.
|
||||
* \p output is an output buffer of the resulting HMAC operation.
|
||||
* Must return 0 if error, or the length in bytes of the HMAC operation.
|
||||
*/
|
||||
typedef int (*TOTP_ALGO)(
|
||||
const uint8_t* key,
|
||||
size_t key_length,
|
||||
@@ -22,27 +21,32 @@ typedef int (*TOTP_ALGO)(
|
||||
size_t input_length,
|
||||
uint8_t* output);
|
||||
|
||||
/*
|
||||
Computes HMAC using SHA1
|
||||
*/
|
||||
/**
|
||||
* @brief Computes HMAC using SHA1
|
||||
*/
|
||||
extern const TOTP_ALGO TOTP_ALGO_SHA1;
|
||||
|
||||
/*
|
||||
Computes HMAC using SHA256
|
||||
*/
|
||||
/**
|
||||
* @brief Computes HMAC using SHA256
|
||||
*/
|
||||
extern const TOTP_ALGO TOTP_ALGO_SHA256;
|
||||
|
||||
/*
|
||||
Computes HMAC using SHA512
|
||||
*/
|
||||
/**
|
||||
* @brief Computes HMAC using SHA512
|
||||
*/
|
||||
extern const TOTP_ALGO TOTP_ALGO_SHA512;
|
||||
|
||||
/*
|
||||
Computes TOTP token
|
||||
Returns:
|
||||
TOTP token on success
|
||||
0 otherwise
|
||||
*/
|
||||
/**
|
||||
* @brief Generates a OTP key using the totp algorithm.
|
||||
* @param algo hashing algorithm to be used
|
||||
* @param digits desired TOTP code length
|
||||
* @param plain_secret plain token secret
|
||||
* @param plain_secret_length plain token secret length
|
||||
* @param for_time the time the generated key will be created for
|
||||
* @param timezone UTC timezone adjustment for the generated key
|
||||
* @param interval token lifetime in seconds
|
||||
* @return TOTP code if code was successfully generated; 0 otherwise
|
||||
*/
|
||||
uint32_t totp_at(
|
||||
TOTP_ALGO algo,
|
||||
uint8_t digits,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "ui_controls.h"
|
||||
#include <Authenticator_icons.h>
|
||||
#include <totp_icons.h>
|
||||
#include "constants.h"
|
||||
|
||||
#define TEXT_BOX_HEIGHT 13
|
||||
|
||||
@@ -3,11 +3,29 @@
|
||||
#include <inttypes.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
/**
|
||||
* @brief Renders TextBox control
|
||||
* @param canvas canvas to render control at
|
||||
* @param y vertical position of a control to be rendered at
|
||||
* @param text text to be rendered inside control
|
||||
* @param is_selected whether control should be rendered as focused or not
|
||||
*/
|
||||
void ui_control_text_box_render(
|
||||
Canvas* const canvas,
|
||||
int16_t y,
|
||||
const char* text,
|
||||
bool is_selected);
|
||||
|
||||
/**
|
||||
* @brief Renders Button control
|
||||
* @param canvas canvas to render control at
|
||||
* @param x horizontal position of a control to be rendered at
|
||||
* @param y vertical position of a control to be rendered at
|
||||
* @param width control width
|
||||
* @param height control height
|
||||
* @param text text to be rendered inside control
|
||||
* @param is_selected whether control should be rendered as focused or not
|
||||
*/
|
||||
void ui_control_button_render(
|
||||
Canvas* const canvas,
|
||||
int16_t x,
|
||||
@@ -16,6 +34,16 @@ void ui_control_button_render(
|
||||
uint8_t height,
|
||||
const char* text,
|
||||
bool is_selected);
|
||||
|
||||
/**
|
||||
* @brief Renders Select control
|
||||
* @param canvas canvas to render control at
|
||||
* @param x horizontal position of a control to be rendered at
|
||||
* @param y vertical position of a control to be rendered at
|
||||
* @param width control width
|
||||
* @param text text to be rendered inside control
|
||||
* @param is_selected whether control should be rendered as focused or not
|
||||
*/
|
||||
void ui_control_select_render(
|
||||
Canvas* const canvas,
|
||||
int16_t x,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
|
||||
if(plugin_state != NULL && !plugin_state->changing_scene) {
|
||||
if (plugin_state != NULL && !plugin_state->changing_scene) {
|
||||
totp_scene_director_render(canvas, plugin_state);
|
||||
}
|
||||
|
||||
@@ -49,43 +49,29 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||
|
||||
totp_scene_director_init_scenes(plugin_state);
|
||||
|
||||
if(plugin_state->crypto_verify_data == NULL) {
|
||||
if (plugin_state->crypto_verify_data == NULL) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, "No", NULL, "Yes");
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Would you like to setup PIN?",
|
||||
SCREEN_WIDTH_CENTER,
|
||||
SCREEN_HEIGHT_CENTER,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
dialog_message_set_text(message, "Would you like to setup PIN?", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter);
|
||||
DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
if(dialog_result == DialogMessageButtonRight) {
|
||||
if (dialog_result == DialogMessageButtonRight) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
||||
} else {
|
||||
totp_crypto_seed_iv(plugin_state, NULL, 0);
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
}
|
||||
} else if(plugin_state->pin_set) {
|
||||
} else if (plugin_state->pin_set) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
|
||||
} else {
|
||||
totp_crypto_seed_iv(plugin_state, NULL, 0);
|
||||
if(totp_crypto_verify_key(plugin_state)) {
|
||||
if (totp_crypto_verify_key(plugin_state)) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
LOGGING_TAG,
|
||||
"Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other");
|
||||
FURI_LOG_E(LOGGING_TAG, "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other");
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, "Exit", NULL, NULL);
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Digital signature verification failed",
|
||||
SCREEN_WIDTH_CENTER,
|
||||
SCREEN_HEIGHT_CENTER,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
dialog_message_set_text(message, "Digital signature verification failed", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter);
|
||||
dialog_message_show(plugin_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
return false;
|
||||
@@ -108,7 +94,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
|
||||
|
||||
ListNode* node = plugin_state->tokens_list;
|
||||
ListNode* tmp;
|
||||
while(node != NULL) {
|
||||
while (node != NULL) {
|
||||
tmp = node->next;
|
||||
TokenInfo* tokenInfo = node->data;
|
||||
token_info_free(tokenInfo);
|
||||
@@ -116,7 +102,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
|
||||
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);
|
||||
@@ -127,7 +113,7 @@ int32_t totp_app() {
|
||||
PluginState* plugin_state = malloc(sizeof(PluginState));
|
||||
furi_check(plugin_state != NULL);
|
||||
|
||||
if(!totp_plugin_state_init(plugin_state)) {
|
||||
if (!totp_plugin_state_init(plugin_state)) {
|
||||
FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n");
|
||||
totp_plugin_state_free(plugin_state);
|
||||
return 254;
|
||||
@@ -152,20 +138,18 @@ int32_t totp_app() {
|
||||
bool processing = true;
|
||||
uint32_t last_user_interaction_time = furi_get_tick();
|
||||
while(processing) {
|
||||
if(plugin_state->changing_scene) continue;
|
||||
if (plugin_state->changing_scene) continue;
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
PluginState* plugin_state_m = acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.type == EventTypeKey) {
|
||||
if (event.type == EventTypeKey) {
|
||||
last_user_interaction_time = furi_get_tick();
|
||||
}
|
||||
|
||||
processing = totp_scene_director_handle_event(&event, plugin_state_m);
|
||||
} else if(
|
||||
plugin_state_m->pin_set && plugin_state_m->current_scene != TotpSceneAuthentication &&
|
||||
furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
|
||||
} else if (plugin_state_m->pin_set && plugin_state_m->current_scene != TotpSceneAuthentication && furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
|
||||
totp_scene_director_activate_scene(plugin_state_m, TotpSceneAuthentication, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,22 +8,82 @@
|
||||
|
||||
#define TOTP_IV_SIZE 16
|
||||
|
||||
/**
|
||||
* @brief Application state structure
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Application current scene
|
||||
*/
|
||||
Scene current_scene;
|
||||
|
||||
/**
|
||||
* @brief Application current scene state
|
||||
*/
|
||||
void* current_scene_state;
|
||||
|
||||
/**
|
||||
* @brief Whether scene is changing now
|
||||
*/
|
||||
bool changing_scene;
|
||||
|
||||
/**
|
||||
* @brief Reference to the firmware notification subsystem
|
||||
*/
|
||||
NotificationApp* notification;
|
||||
|
||||
/**
|
||||
* @brief Reference to the firmware dialogs subsystem
|
||||
*/
|
||||
DialogsApp* dialogs;
|
||||
|
||||
/**
|
||||
* @brief Reference to the firmware GUI subsystem
|
||||
*/
|
||||
Gui* gui;
|
||||
|
||||
/**
|
||||
* @brief Timezone UTC offset in hours
|
||||
*/
|
||||
float timezone_offset;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
uint8_t* crypto_verify_data;
|
||||
|
||||
/**
|
||||
* @brief Encrypted well-known string data length
|
||||
*/
|
||||
size_t crypto_verify_data_length;
|
||||
|
||||
/**
|
||||
* @brief Whether PIN is set by user or not
|
||||
*/
|
||||
bool pin_set;
|
||||
|
||||
/**
|
||||
* @brief Initialization vector (IV) to be used for encryption\decryption
|
||||
*/
|
||||
uint8_t iv[TOTP_IV_SIZE];
|
||||
|
||||
/**
|
||||
* @brief Basic randomly-generated initialization vector (IV)
|
||||
*/
|
||||
uint8_t base_iv[TOTP_IV_SIZE];
|
||||
} PluginState;
|
||||
|
||||
@@ -2,25 +2,102 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo;
|
||||
/**
|
||||
* @brief Hashing algorithm to be used to generate token
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief SHA1 hashing algorithm
|
||||
*/
|
||||
SHA1,
|
||||
|
||||
typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount;
|
||||
/**
|
||||
* @brief SHA256 hashing algorithm
|
||||
*/
|
||||
SHA256,
|
||||
|
||||
/**
|
||||
* @brief SHA512 hashing algorithm
|
||||
*/
|
||||
SHA512
|
||||
} TokenHashAlgo;
|
||||
|
||||
/**
|
||||
* @brief Token digits count to be generated.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 6 digits
|
||||
*/
|
||||
TOTP_6_DIGITS,
|
||||
|
||||
/**
|
||||
* @brief 8 digits
|
||||
*/
|
||||
TOTP_8_DIGITS
|
||||
} TokenDigitsCount;
|
||||
|
||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT 8
|
||||
|
||||
/**
|
||||
* @brief TOTP token information
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Encrypted token secret
|
||||
*/
|
||||
uint8_t* token;
|
||||
|
||||
/**
|
||||
* @brief Encrypted token secret length
|
||||
*/
|
||||
size_t token_length;
|
||||
|
||||
/**
|
||||
* @brief User-friendly token name
|
||||
*/
|
||||
char* name;
|
||||
|
||||
/**
|
||||
* @brief Hashing algorithm
|
||||
*/
|
||||
TokenHashAlgo algo;
|
||||
|
||||
/**
|
||||
* @brief Desired TOTP token length
|
||||
*/
|
||||
TokenDigitsCount digits;
|
||||
} TokenInfo;
|
||||
|
||||
/**
|
||||
* @brief Allocates a new instance of \c TokenInfo
|
||||
* @return
|
||||
*/
|
||||
TokenInfo* token_info_alloc();
|
||||
|
||||
/**
|
||||
* @brief Disposes all the resources allocated by the given \c TokenInfo instance
|
||||
* @param token_info instance to be disposed
|
||||
*/
|
||||
void token_info_free(TokenInfo* token_info);
|
||||
|
||||
/**
|
||||
* @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo
|
||||
* @param token_info instance where secret should be updated
|
||||
* @param base32_token_secret plain token secret in Base32 format
|
||||
* @param token_secret_length plain token secret length
|
||||
* @param iv initialization vecor (IV) to be used for encryption
|
||||
* @return \c true if token successfully set; \c false otherwise
|
||||
*/
|
||||
bool token_info_set_secret(
|
||||
TokenInfo* token_info,
|
||||
const char* base32_token_secret,
|
||||
size_t token_secret_length,
|
||||
const uint8_t* iv);
|
||||
|
||||
/**
|
||||
* @brief Gets token digits count as \c uint8_t type
|
||||
* @param token_info instance which's desired digits count should be returned
|
||||
* @return Token digits length as \c uint8_t type
|
||||
*/
|
||||
uint8_t token_info_get_digits_count(const TokenInfo* token_info);
|
||||
|
||||
Reference in New Issue
Block a user