From f5ff6438d11c44e33a8e7178499b43ccc0084208 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 19 Sep 2022 11:43:53 -0500 Subject: [PATCH] NFC user dict list, delete, and de-duplication. (#1533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add MFC user keys list * Leakey submenu fix * Set next target for Save/Delete success scenes * Delete individual user keys * Update count of total keys * Fix memory leak * Check for duplicate keys * Remove a submodule that I never added? * Swap and position icons * Revamp according to design doc * Rename icons to include size and replace keychain icon with smaller variant * Fix typos * Final fixes * Fufill requested changes * Cleanup comments * Merge dev after SD app loading * Fixing icon names * Revert merge mistakes and API version * Scene switching adjustments * F7: add/change/remove some nfc icons in api_symbols.csv Co-authored-by: あく --- .vscode/example/settings.json | 2 +- .../main/lfrfid/views/lfrfid_view_read.c | 2 +- applications/main/nfc/nfc_i.h | 5 + .../main/nfc/scenes/nfc_scene_config.h | 3 + .../nfc/scenes/nfc_scene_delete_success.c | 9 +- .../nfc/scenes/nfc_scene_dict_not_found.c | 5 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 24 +- .../scenes/nfc_scene_mf_classic_keys_add.c | 13 +- .../scenes/nfc_scene_mf_classic_keys_delete.c | 77 ++++++ .../scenes/nfc_scene_mf_classic_keys_list.c | 60 +++++ ...nfc_scene_mf_classic_keys_warn_duplicate.c | 47 ++++ .../nfc_scene_mf_ultralight_read_auth.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 2 +- .../nfc_scene_restore_original_confirm.c | 2 +- .../main/nfc/scenes/nfc_scene_save_success.c | 5 +- .../bt_hid_app/views/bt_hid_keyboard.c | 2 +- .../plugins/bt_hid_app/views/bt_hid_mouse.c | 2 +- .../desktop/views/desktop_view_pin_input.c | 2 +- assets/icons/NFC/Keychain.png | Bin 3750 -> 0 bytes assets/icons/NFC/Keychain_39x36.png | Bin 0 -> 3775 bytes .../{NFC_manual.png => NFC_manual_60x50.png} | Bin assets/icons/NFC/Reader_detect_43x40.png | Bin 0 -> 3799 bytes .../{Restoring.png => Restoring_38x32.png} | Bin ...n_arrow_up7x9.png => Pin_arrow_up_7x9.png} | Bin firmware/targets/f7/api_symbols.csv | 11 +- lib/nfc/helpers/mf_classic_dict.c | 230 +++++++++++++++--- lib/nfc/helpers/mf_classic_dict.h | 22 +- 28 files changed, 465 insertions(+), 64 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c delete mode 100644 assets/icons/NFC/Keychain.png create mode 100644 assets/icons/NFC/Keychain_39x36.png rename assets/icons/NFC/{NFC_manual.png => NFC_manual_60x50.png} (100%) create mode 100644 assets/icons/NFC/Reader_detect_43x40.png rename assets/icons/NFC/{Restoring.png => Restoring_38x32.png} (100%) rename assets/icons/PIN/{Pin_arrow_up7x9.png => Pin_arrow_up_7x9.png} (100%) diff --git a/.vscode/example/settings.json b/.vscode/example/settings.json index d2917a90..d84707e0 100644 --- a/.vscode/example/settings.json +++ b/.vscode/example/settings.json @@ -22,4 +22,4 @@ "SConstruct": "python", "*.fam": "python", } -} \ No newline at end of file +} diff --git a/applications/main/lfrfid/views/lfrfid_view_read.c b/applications/main/lfrfid/views/lfrfid_view_read.c index 2b63175d..66caf8df 100644 --- a/applications/main/lfrfid/views/lfrfid_view_read.c +++ b/applications/main/lfrfid/views/lfrfid_view_read.c @@ -16,7 +16,7 @@ static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) { LfRfidReadViewModel* model = _model; canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, 0, 8, &I_NFC_manual); + canvas_draw_icon(canvas, 0, 8, &I_NFC_manual_60x50); canvas_set_font(canvas, FontPrimary); diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h index 60e1c199..15ea5348 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -37,6 +37,10 @@ #include "rpc/rpc_app.h" +#include + +ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); + #define NFC_TEXT_STORE_SIZE 128 typedef enum { @@ -60,6 +64,7 @@ struct Nfc { char text_store[NFC_TEXT_STORE_SIZE + 1]; string_t text_box_store; uint8_t byte_input_store[6]; + MfClassicUserKeys_t mfc_key_strs; // Used in MFC key listing void* rpc_ctx; NfcRpcState rpc_state; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 540fe109..a25850c8 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -32,6 +32,9 @@ ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) +ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) +ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) +ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_menu, EmvMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index 713b99eb..1664a9e5 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -25,8 +25,13 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } } } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c index dc21b08b..781c5a93 100644 --- a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c +++ b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c @@ -31,7 +31,10 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneExtraActions); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 43e49e5a..e888e9d3 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -17,7 +17,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { submenu_add_item( submenu, - "Mf Classic Keys", + "Mifare Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c index fcb8bc18..a2e6ae74 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -26,15 +26,25 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { } widget_add_string_element( - nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys"); + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Mifare Classic Keys"); char temp_str[32]; - snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "Flipper list: %ld", flipper_dict_keys_total); widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "User list: %ld", user_dict_keys_total); widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); widget_add_button_element( nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); - widget_add_icon_element(nfc->widget, 90, 12, &I_Keychain); + widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_mf_classic_keys_widget_callback, nfc); + widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); + if(user_dict_keys_total > 0) { + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "List", + nfc_scene_mf_classic_keys_widget_callback, + nfc); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -47,6 +57,12 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) if(event.event == GuiButtonTypeCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); consumed = true; + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(nfc->scene_manager); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); + consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c index 9f56b0f4..2921d21c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -29,15 +29,16 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { // Add key to dict - bool key_added = false; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); if(dict) { - if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { - key_added = true; + if(mf_classic_dict_is_key_present(dict, nfc->byte_input_store)) { + scene_manager_next_scene( + nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); + } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } - } - if(key_added) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c new file mode 100644 index 00000000..16a189da --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c @@ -0,0 +1,77 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_delete_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { + Nfc* nfc = context; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + // Setup Custom Widget view + string_t key_str; + string_init(key_str); + + widget_add_string_element( + nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?"); + widget_add_button_element( + nfc->widget, + GuiButtonTypeLeft, + "Cancel", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "Delete", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + + mf_classic_dict_get_key_at_index_str(dict, key_str, key_index); + widget_add_string_element( + nfc->widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(key_str)); + + string_clear(key_str); + mf_classic_dict_free(dict); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(event.event == GuiButtonTypeRight) { + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(mf_classic_dict_delete_index(dict, key_index)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } + mf_classic_dict_free(dict); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c new file mode 100644 index 00000000..36f01897 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c @@ -0,0 +1,60 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_classic_keys_list_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + uint32_t index = 0; + string_t temp_key; + MfClassicUserKeys_init(nfc->mfc_key_strs); + string_init(temp_key); + if(dict) { + mf_classic_dict_rewind(dict); + while(mf_classic_dict_get_next_key_str(dict, temp_key)) { + char* current_key = (char*)malloc(sizeof(char) * 13); + strncpy(current_key, string_get_cstr(temp_key), 12); + MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); + FURI_LOG_D("ListKeys", "Key %d: %s", index, current_key); + submenu_add_item( + submenu, + current_key, + index++, + nfc_scene_mf_classic_keys_list_submenu_callback, + nfc); + } + } + submenu_set_header(submenu, "Select key to delete:"); + mf_classic_dict_free(dict); + string_clear(temp_key); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicKeysDelete, event.event); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + consumed = true; + } + return consumed; +} + +void nfc_scene_mf_classic_keys_list_on_exit(void* context) { + Nfc* nfc = context; + + MfClassicUserKeys_it_t it; + for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); + MfClassicUserKeys_next(it)) { + free(*MfClassicUserKeys_ref(it)); + } + MfClassicUserKeys_clear(nfc->mfc_key_strs); + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c new file mode 100644 index 00000000..ab41989b --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -0,0 +1,47 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); + popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Please enter a\n" + "different key.", + 4, + 24, + AlignLeft, + AlignTop); + popup_set_timeout(popup, 5000); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeysAdd); + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { + Nfc* nfc = context; + + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 1a106bdb..25008004 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -27,7 +27,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState popup_reset(nfc->popup); popup_set_text( nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); } else if(state == NfcSceneMfUlReadStateReading) { popup_reset(nfc->popup); popup_set_header( diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index da21b9f3..e6df476f 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -26,7 +26,7 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { popup_reset(nfc->popup); popup_set_text( nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); } else if(state == NfcSceneReadStateReading) { popup_reset(nfc->popup); popup_set_header( diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c index 2c12749d..730dd41e 100644 --- a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c @@ -11,7 +11,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring); + dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32); dialog_ex_set_text( dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Cancel"); diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index a3b17451..dcd2519f 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -27,7 +27,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneSavedMenu); } else { diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c index 1088e295..3617dc0f 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c @@ -109,7 +109,7 @@ const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, }, { - {.width = 1, .icon = &I_Pin_arrow_up7x9, .value = HID_KEYBOARD_L_SHIFT}, + {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, diff --git a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c index f9d84f9f..395cb52c 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c @@ -53,7 +53,7 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9); + canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); canvas_set_color(canvas, ColorBlack); // Down diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index 5502d5f6..bf05f06b 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -117,7 +117,7 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_down_7x9); break; case InputKeyUp: - canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up7x9); + canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up_7x9); break; case InputKeyLeft: canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_left_9x7); diff --git a/assets/icons/NFC/Keychain.png b/assets/icons/NFC/Keychain.png deleted file mode 100644 index 7ba1b11da6fde4e2b4b148a35593937f2a2ac471..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3750 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 } -bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { - furi_assert(dict); - furi_assert(dict->stream); - - uint8_t key_byte_tmp = 0; - string_t next_line; - string_init(next_line); - - bool key_read = false; - *key = 0ULL; - while(!key_read) { - if(!stream_read_line(dict->stream, next_line)) break; - if(string_get_char(next_line, 0) == '#') continue; - if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - for(uint8_t i = 0; i < 12; i += 2) { - args_char_to_hex( - string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp); - *key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2); - } - key_read = true; - } - - string_clear(next_line); - return key_read; -} - bool mf_classic_dict_rewind(MfClassicDict* dict) { furi_assert(dict); furi_assert(dict->stream); @@ -125,24 +117,194 @@ bool mf_classic_dict_rewind(MfClassicDict* dict) { return stream_rewind(dict->stream); } -bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) { +bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, string_t key) { furi_assert(dict); furi_assert(dict->stream); - string_t key_str; - string_init(key_str); - for(size_t i = 0; i < 6; i++) { - string_cat_printf(key_str, "%02X", key[i]); + bool key_read = false; + string_reset(key); + while(!key_read) { + if(!stream_read_line(dict->stream, key)) break; + if(string_get_char(key, 0) == '#') continue; + if(string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(key, 12); + key_read = true; } - string_cat_printf(key_str, "\n"); + + return key_read; +} + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + bool key_read = mf_classic_dict_get_next_key_str(dict, temp_key); + if(key_read) { + mf_classic_dict_str_to_int(temp_key, key); + } + string_clear(temp_key); + return key_read; +} + +bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, string_t key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + + bool key_found = false; + stream_rewind(dict->stream); + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(next_line, 12); + if(!string_equal_p(key, next_line)) continue; + key_found = true; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) { + string_t temp_key; + + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_found = mf_classic_dict_is_key_present_str(dict, temp_key); + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_add_key_str(MfClassicDict* dict, string_t key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_cat_printf(key, "\n"); bool key_added = false; do { if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break; - if(!stream_insert_string(dict->stream, key_str)) break; + if(!stream_insert_string(dict->stream, key)) break; + dict->total_keys++; key_added = true; } while(false); - string_clear(key_str); + string_left(key, 12); return key_added; } + +bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_added = mf_classic_dict_add_key_str(dict, temp_key); + + string_clear(temp_key); + return key_added; +} + +bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + uint32_t index = 0; + string_init(next_line); + string_reset(key); + + bool key_found = false; + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + string_set_n(key, next_line, 0, 12); + key_found = true; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + bool key_found = mf_classic_dict_get_key_at_index_str(dict, temp_key, target); + if(key_found) { + mf_classic_dict_str_to_int(temp_key, key); + } + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_t key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + + bool key_found = false; + uint32_t index = 0; + stream_rewind(dict->stream); + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(next_line, 12); + if(!string_equal_p(key, next_line)) continue; + key_found = true; + *target = index; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_found = mf_classic_dict_find_index_str(dict, temp_key, target); + + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + uint32_t index = 0; + + bool key_removed = false; + while(!key_removed) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); + if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; + dict->total_keys--; + key_removed = true; + } + + string_clear(next_line); + return key_removed; +} diff --git a/lib/nfc/helpers/mf_classic_dict.h b/lib/nfc/helpers/mf_classic_dict.h index 2654e668..aaea3c40 100644 --- a/lib/nfc/helpers/mf_classic_dict.h +++ b/lib/nfc/helpers/mf_classic_dict.h @@ -21,8 +21,26 @@ void mf_classic_dict_free(MfClassicDict* dict); uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict); -bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key); - bool mf_classic_dict_rewind(MfClassicDict* dict); +bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key); + +bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key); + +bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target); + +bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target); + bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key); + +bool mf_classic_dict_add_key_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target); + +bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_t key, uint32_t* target); + +bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target);