From 560ea5f995df0a179632bcdae9075599d97a214f Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 Aug 2022 18:08:13 +0300 Subject: [PATCH] [FL-2714] New NFC info screens (#1605) * nfc: add scroll element for info * widget: format lines for scroll text element * widget: fix new line generation * widget: finish element text scroll * nfc: rework ultralight and NTAG info scenes * nfc: rework mf classic info screens * nfc: rework nfca info scenes * nfc: fix mf ultralight navigation * widget: add documentation * nfc: rework bank card infO * nfc: rework device info scene * nfc: fix incorrect atqa order * mf ultralight: remove unused function * widget: add mutex for model protection * widget: fix memory leak * nfc: rework delete scene * nfc: fix selected item in saved menu scene * widget: fix naming in text scroll element * nfc: fix navigation from delete success * nfc: add dictionary icon * widget: fix memory leak --- applications/gui/modules/widget.c | 13 + applications/gui/modules/widget.h | 21 ++ .../widget_elements/widget_element_i.h | 8 + .../widget_element_text_scroll.c | 245 ++++++++++++++++++ applications/nfc/nfc.c | 9 - applications/nfc/nfc_i.h | 4 +- applications/nfc/scenes/nfc_scene_config.h | 6 +- applications/nfc/scenes/nfc_scene_delete.c | 69 ++--- .../nfc/scenes/nfc_scene_delete_success.c | 2 +- .../nfc/scenes/nfc_scene_device_info.c | 217 +++------------- applications/nfc/scenes/nfc_scene_emv_menu.c | 54 ++++ .../nfc/scenes/nfc_scene_emv_read_success.c | 104 +++----- .../nfc/scenes/nfc_scene_file_select.c | 1 + .../nfc/scenes/nfc_scene_mf_classic_info.c | 72 ----- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 1 + .../nfc/scenes/nfc_scene_mf_classic_menu.c | 2 +- .../nfc_scene_mf_classic_read_success.c | 43 +-- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 17 ++ .../nfc_scene_mf_desfire_read_success.c | 101 ++++---- .../nfc/scenes/nfc_scene_mf_ultralight_data.c | 32 +++ .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 7 + .../nfc_scene_mf_ultralight_read_success.c | 74 +----- .../nfc/scenes/nfc_scene_nfc_data_info.c | 133 ++++++++++ applications/nfc/scenes/nfc_scene_nfca_menu.c | 62 +++++ .../nfc/scenes/nfc_scene_nfca_read_success.c | 72 +++++ applications/nfc/scenes/nfc_scene_read.c | 7 +- .../nfc/scenes/nfc_scene_read_card_success.c | 43 +-- .../nfc/scenes/nfc_scene_saved_menu.c | 18 +- applications/nfc/views/bank_card.c | 80 ------ applications/nfc/views/bank_card.h | 26 -- assets/icons/NFC/Keychain.png | Bin 0 -> 3750 bytes lib/nfc/nfc_device.c | 1 + lib/nfc/nfc_worker.c | 2 +- lib/nfc/parsers/nfc_supported_card.c | 14 + lib/nfc/parsers/nfc_supported_card.h | 5 +- lib/nfc/parsers/troyka_parser.c | 42 +-- lib/nfc/parsers/troyka_parser.h | 2 +- lib/nfc/protocols/mifare_ultralight.c | 44 +--- lib/nfc/protocols/mifare_ultralight.h | 12 - 39 files changed, 918 insertions(+), 747 deletions(-) create mode 100644 applications/gui/modules/widget_elements/widget_element_text_scroll.c create mode 100644 applications/nfc/scenes/nfc_scene_emv_menu.c delete mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_info.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_data.c create mode 100644 applications/nfc/scenes/nfc_scene_nfc_data_info.c create mode 100644 applications/nfc/scenes/nfc_scene_nfca_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_nfca_read_success.c delete mode 100755 applications/nfc/views/bank_card.c delete mode 100644 applications/nfc/views/bank_card.h create mode 100644 assets/icons/NFC/Keychain.png diff --git a/applications/gui/modules/widget.c b/applications/gui/modules/widget.c index 8d7acb013..b37a64701 100644 --- a/applications/gui/modules/widget.c +++ b/applications/gui/modules/widget.c @@ -162,6 +162,19 @@ void widget_add_text_box_element( widget_add_element(widget, text_box_element); } +void widget_add_text_scroll_element( + Widget* widget, + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const char* text) { + furi_assert(widget); + WidgetElement* text_scroll_element = + widget_element_text_scroll_create(x, y, width, height, text); + widget_add_element(widget, text_scroll_element); +} + void widget_add_button_element( Widget* widget, GuiButtonType button_type, diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h index 55af59d7c..587fa3c65 100755 --- a/applications/gui/modules/widget.h +++ b/applications/gui/modules/widget.h @@ -105,6 +105,27 @@ void widget_add_text_box_element( const char* text, bool strip_to_dots); +/** Add Text Scroll Element + * + * @param widget Widget instance + * @param x x coordinate + * @param y y coordinate + * @param width width to fit text + * @param height height to fit text + * @param[in] text Formatted text. Default format: align left, Secondary font. + * The following formats are available: + * "\e#Bold text" - sets bold font before until next '\n' symbol + * "\ecBold text" - sets center horizontal align before until next '\n' symbol + * "\erBold text" - sets right horizontal align before until next '\n' symbol + */ +void widget_add_text_scroll_element( + Widget* widget, + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const char* text); + /** Add Button Element * * @param widget Widget instance diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/gui/modules/widget_elements/widget_element_i.h index bcbd4afdb..316ed7400 100755 --- a/applications/gui/modules/widget_elements/widget_element_i.h +++ b/applications/gui/modules/widget_elements/widget_element_i.h @@ -29,6 +29,7 @@ struct WidgetElement { // generic model holder void* model; + FuriMutex* model_mutex; // pointer to widget that hold our element Widget* parent; @@ -80,3 +81,10 @@ WidgetElement* widget_element_frame_create( uint8_t width, uint8_t height, uint8_t radius); + +WidgetElement* widget_element_text_scroll_create( + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const char* text); diff --git a/applications/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/gui/modules/widget_elements/widget_element_text_scroll.c new file mode 100644 index 000000000..6682b106a --- /dev/null +++ b/applications/gui/modules/widget_elements/widget_element_text_scroll.c @@ -0,0 +1,245 @@ +#include "widget_element_i.h" +#include +#include +#include + +#define WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET (4) + +typedef struct { + Font font; + Align horizontal; + string_t text; +} TextScrollLineArray; + +ARRAY_DEF(TextScrollLineArray, TextScrollLineArray, M_POD_OPLIST) + +typedef struct { + TextScrollLineArray_t line_array; + uint8_t x; + uint8_t y; + uint8_t width; + uint8_t height; + string_t text; + uint8_t scroll_pos_total; + uint8_t scroll_pos_current; + bool text_formatted; +} WidgetElementTextScrollModel; + +static bool + widget_element_text_scroll_process_ctrl_symbols(TextScrollLineArray* line, string_t text) { + bool processed = false; + + do { + if(string_get_char(text, 0) != '\e') break; + char ctrl_symbol = string_get_char(text, 1); + if(ctrl_symbol == 'c') { + line->horizontal = AlignCenter; + } else if(ctrl_symbol == 'r') { + line->horizontal = AlignRight; + } else if(ctrl_symbol == '#') { + line->font = FontPrimary; + } + string_right(text, 2); + processed = true; + } while(false); + + return processed; +} + +void widget_element_text_scroll_add_line(WidgetElement* element, TextScrollLineArray* line) { + WidgetElementTextScrollModel* model = element->model; + TextScrollLineArray new_line; + new_line.font = line->font; + new_line.horizontal = line->horizontal; + string_init_set(new_line.text, line->text); + TextScrollLineArray_push_back(model->line_array, new_line); +} + +static void widget_element_text_scroll_fill_lines(Canvas* canvas, WidgetElement* element) { + WidgetElementTextScrollModel* model = element->model; + TextScrollLineArray line_tmp; + bool all_text_processed = false; + string_init(line_tmp.text); + bool reached_new_line = true; + uint16_t total_height = 0; + + while(!all_text_processed) { + if(reached_new_line) { + // Set default line properties + line_tmp.font = FontSecondary; + line_tmp.horizontal = AlignLeft; + string_reset(line_tmp.text); + // Process control symbols + while(widget_element_text_scroll_process_ctrl_symbols(&line_tmp, model->text)) + ; + } + // Set canvas font + canvas_set_font(canvas, line_tmp.font); + CanvasFontParameters* params = canvas_get_font_params(canvas, line_tmp.font); + total_height += params->height; + if(total_height > model->height) { + model->scroll_pos_total++; + } + + uint8_t line_width = 0; + uint16_t char_i = 0; + while(true) { + char next_char = string_get_char(model->text, char_i++); + if(next_char == '\0') { + string_push_back(line_tmp.text, '\0'); + widget_element_text_scroll_add_line(element, &line_tmp); + total_height += params->leading_default - params->height; + all_text_processed = true; + break; + } else if(next_char == '\n') { + string_push_back(line_tmp.text, '\0'); + widget_element_text_scroll_add_line(element, &line_tmp); + string_right(model->text, char_i); + total_height += params->leading_default - params->height; + reached_new_line = true; + break; + } else { + line_width += canvas_glyph_width(canvas, next_char); + if(line_width > model->width) { + string_push_back(line_tmp.text, '\0'); + widget_element_text_scroll_add_line(element, &line_tmp); + string_right(model->text, char_i - 1); + string_reset(line_tmp.text); + total_height += params->leading_default - params->height; + reached_new_line = false; + break; + } else { + string_push_back(line_tmp.text, next_char); + } + } + } + } + + string_clear(line_tmp.text); +} + +static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* element) { + furi_assert(canvas); + furi_assert(element); + + furi_mutex_acquire(element->model_mutex, FuriWaitForever); + + WidgetElementTextScrollModel* model = element->model; + if(!model->text_formatted) { + widget_element_text_scroll_fill_lines(canvas, element); + model->text_formatted = true; + } + + uint8_t y = model->y; + uint8_t x = model->x; + uint16_t curr_line = 0; + if(TextScrollLineArray_size(model->line_array)) { + TextScrollLineArray_it_t it; + for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it); + TextScrollLineArray_next(it), curr_line++) { + if(curr_line < model->scroll_pos_current) continue; + TextScrollLineArray* line = TextScrollLineArray_ref(it); + CanvasFontParameters* params = canvas_get_font_params(canvas, line->font); + if(y + params->descender > model->y + model->height) break; + canvas_set_font(canvas, line->font); + if(line->horizontal == AlignLeft) { + x = model->x; + } else if(line->horizontal == AlignCenter) { + x = (model->x + model->width) / 2; + } else if(line->horizontal == AlignRight) { + x = model->x + model->width; + } + canvas_draw_str_aligned( + canvas, x, y, line->horizontal, AlignTop, string_get_cstr(line->text)); + y += params->leading_default; + } + // Draw scroll bar + if(model->scroll_pos_total > 1) { + elements_scrollbar_pos( + canvas, + model->x + model->width + WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET, + model->y, + model->height, + model->scroll_pos_current, + model->scroll_pos_total); + } + } + + furi_mutex_release(element->model_mutex); +} + +static bool widget_element_text_scroll_input(InputEvent* event, WidgetElement* element) { + furi_assert(event); + furi_assert(element); + + furi_mutex_acquire(element->model_mutex, FuriWaitForever); + + WidgetElementTextScrollModel* model = element->model; + bool consumed = false; + + if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { + if(event->key == InputKeyUp) { + if(model->scroll_pos_current > 0) { + model->scroll_pos_current--; + } + consumed = true; + } else if(event->key == InputKeyDown) { + if((model->scroll_pos_total > 1) && + (model->scroll_pos_current < model->scroll_pos_total - 1)) { + model->scroll_pos_current++; + } + consumed = true; + } + } + + furi_mutex_release(element->model_mutex); + + return consumed; +} + +static void widget_element_text_scroll_free(WidgetElement* text_scroll) { + furi_assert(text_scroll); + + WidgetElementTextScrollModel* model = text_scroll->model; + TextScrollLineArray_it_t it; + for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it); + TextScrollLineArray_next(it)) { + TextScrollLineArray* line = TextScrollLineArray_ref(it); + string_clear(line->text); + } + TextScrollLineArray_clear(model->line_array); + string_clear(model->text); + free(text_scroll->model); + furi_mutex_free(text_scroll->model_mutex); + free(text_scroll); +} + +WidgetElement* widget_element_text_scroll_create( + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const char* text) { + furi_assert(text); + + // Allocate and init model + WidgetElementTextScrollModel* model = malloc(sizeof(WidgetElementTextScrollModel)); + model->x = x; + model->y = y; + model->width = width - WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET; + model->height = height; + model->scroll_pos_current = 0; + model->scroll_pos_total = 1; + TextScrollLineArray_init(model->line_array); + string_init_set_str(model->text, text); + + WidgetElement* text_scroll = malloc(sizeof(WidgetElement)); + text_scroll->parent = NULL; + text_scroll->draw = widget_element_text_scroll_draw; + text_scroll->input = widget_element_text_scroll_input; + text_scroll->free = widget_element_text_scroll_free; + text_scroll->model = model; + text_scroll->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + return text_scroll; +} diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index 6b8843db2..3422e91af 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -89,11 +89,6 @@ Nfc* nfc_alloc() { nfc->widget = widget_alloc(); view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); - // Bank Card - nfc->bank_card = bank_card_alloc(); - view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card)); - // Mifare Classic Dict Attack nfc->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( @@ -159,10 +154,6 @@ void nfc_free(Nfc* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); widget_free(nfc->widget); - // Bank Card - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); - bank_card_free(nfc->bank_card); - // Mifare Classic Dict Attack view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); dict_attack_free(nfc->dict_attack); diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 5a916e803..bcfe4a219 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -25,8 +25,8 @@ #include #include #include +#include -#include "views/bank_card.h" #include "views/dict_attack.h" #include @@ -70,7 +70,6 @@ struct Nfc { ByteInput* byte_input; TextBox* text_box; Widget* widget; - BankCard* bank_card; DictAttack* dict_attack; const NfcGenerator* generator; @@ -85,7 +84,6 @@ typedef enum { NfcViewByteInput, NfcViewTextBox, NfcViewWidget, - NfcViewBankCard, NfcViewDictAttack, } NfcView; diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 2b5cb5cf1..ff34a11d8 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -12,7 +12,10 @@ ADD_SCENE(nfc, save_name, SaveName) ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) +ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) +ADD_SCENE(nfc, nfca_menu, NfcaMenu) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) @@ -25,13 +28,13 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) -ADD_SCENE(nfc, mf_classic_info, MfClassicInfo) 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_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) +ADD_SCENE(nfc, emv_menu, EmvMenu) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) ADD_SCENE(nfc, device_info, DeviceInfo) ADD_SCENE(nfc, delete, Delete) @@ -45,3 +48,4 @@ ADD_SCENE(nfc, rpc, Rpc) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, detect_reader, DetectReader) +ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c index 1946b9290..987927e19 100755 --- a/applications/nfc/scenes/nfc_scene_delete.c +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -9,58 +9,43 @@ void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void void nfc_scene_delete_on_enter(void* context) { Nfc* nfc = context; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; // Setup Custom Widget view - char temp_str[64]; - snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name); + string_t temp_str; + string_init(temp_str); + + string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name); widget_add_text_box_element( - nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); + nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, string_get_cstr(temp_str), false); widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); + nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); widget_add_button_element( nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - if(data->uid_len == 4) { - snprintf( - temp_str, - sizeof(temp_str), - "UID: %02X %02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3]); - } else if(data->uid_len == 7) { - snprintf( - temp_str, - sizeof(temp_str), - "UID: %02X %02X %02X %02X %02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3], - data->uid[4], - data->uid[5], - data->uid[6]); - } - widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str); - const char* protocol_name = NULL; + string_set_str(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + widget_add_string_element( + nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str)); + NfcProtocol protocol = nfc->dev->dev_data.protocol; if(protocol == NfcDeviceProtocolEMV) { - protocol_name = nfc_guess_protocol(protocol); + string_set_str(temp_str, "EMV bank card"); } else if(protocol == NfcDeviceProtocolMifareUl) { - protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); + string_set_str(temp_str, nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, true)); + } else if(protocol == NfcDeviceProtocolMifareClassic) { + string_set_str(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); + } else if(protocol == NfcDeviceProtocolMifareDesfire) { + string_set_str(temp_str, "MIFARE DESFire"); + } else { + string_set_str(temp_str, "Unknown ISO tag"); } - if(protocol_name) { - widget_add_string_element( - nfc->widget, 10, 33, AlignLeft, AlignTop, FontSecondary, protocol_name); - } - // TODO change dinamically - widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); - snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); - widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); - widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str); + widget_add_string_element( + nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str)); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + string_clear(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -71,7 +56,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { - return scene_manager_previous_scene(nfc->scene_manager); + consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == GuiButtonTypeRight) { if(nfc_device_delete(nfc->dev, true)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/nfc/scenes/nfc_scene_delete_success.c index 547aeab7e..713b99ebf 100755 --- a/applications/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/nfc/scenes/nfc_scene_delete_success.c @@ -26,7 +26,7 @@ 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, NfcSceneStart); + nfc->scene_manager, NfcSceneFileSelect); } } return consumed; diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index b79c51046..8228c7ea3 100644 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -1,11 +1,6 @@ #include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" -enum { - NfcSceneDeviceInfoUid, - NfcSceneDeviceInfoData, -}; - void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { Nfc* nfc = context; if(type == InputTypeShort) { @@ -13,197 +8,65 @@ void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, } } -void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; - if(result == DialogExResultLeft) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); - } -} - -void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) { - UNUSED(result); - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); - } -} - void nfc_scene_device_info_on_enter(void* context) { Nfc* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; - bool data_display_supported = (nfc->dev->format == NfcDeviceSaveFormatUid) || - (nfc->dev->format == NfcDeviceSaveFormatMifareUl) || - (nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) || - (nfc->dev->format == NfcDeviceSaveFormatBankCard); - // Setup Custom Widget view - widget_add_text_box_element( - nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false); - widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); - if(data_display_supported) { - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); - } - char temp_str[32]; - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - if(data->uid_len == 4) { - snprintf( - temp_str, - sizeof(temp_str), - "UID: %02X %02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3]); - } else if(data->uid_len == 7) { - snprintf( - temp_str, - sizeof(temp_str), - "UID: %02X %02X %02X %02X %02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3], - data->uid[4], - data->uid[5], - data->uid[6]); - } - widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str); + string_t temp_str; + string_init(temp_str); - const char* protocol_name = NULL; - NfcProtocol protocol = nfc->dev->dev_data.protocol; - if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { - protocol_name = nfc_guess_protocol(protocol); - } else if(protocol == NfcDeviceProtocolMifareUl) { - protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); - } else if(protocol == NfcDeviceProtocolMifareClassic) { - protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); - } - if(protocol_name) { - widget_add_string_element( - nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); - } - // TODO change dinamically - widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); - snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); - widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); - widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str); - - // Setup Data View - if(nfc->dev->format == NfcDeviceSaveFormatUid) { - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Back"); - dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { - if(!(i % 8) && i) { - string_push_back(nfc->text_box_store, '\n'); - } - string_cat_printf( - nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); + if(dev_data->protocol == NfcDeviceProtocolEMV) { + EmvData* emv_data = &dev_data->emv_data; + string_printf(temp_str, "\e#%s\n", emv_data->name); + for(uint8_t i = 0; i < emv_data->number_len; i += 2) { + string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); } - text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { - MifareDesfireData* mf_df_data = &nfc->dev->dev_data.mf_df_data; - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = mf_df_data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; - } - } - nfc_text_store_set( - nfc, - "%d application%s, %d file%s", - n_apps, - n_apps == 1 ? "" : "s", - n_files, - n_files == 1 ? "" : "s"); - widget_add_string_element( - nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); - } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - EmvData* emv_data = &nfc->dev->dev_data.emv_data; - BankCard* bank_card = nfc->bank_card; - bank_card_set_name(bank_card, emv_data->name); - bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); - bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc); + string_strim(temp_str); + + // Add expiration date if(emv_data->exp_mon) { - bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); + string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); } - string_t display_str; - string_init(display_str); - if(emv_data->country_code) { + // Parse currency code + if((emv_data->currency_code)) { + string_t currency_name; + string_init(currency_name); + if(nfc_emv_parser_get_currency_name( + nfc->dev->storage, emv_data->currency_code, currency_name)) { + string_cat_printf(temp_str, "\nCur: %s ", string_get_cstr(currency_name)); + } + string_clear(currency_name); + } + // Parse country code + if((emv_data->country_code)) { string_t country_name; string_init(country_name); if(nfc_emv_parser_get_country_name( nfc->dev->storage, emv_data->country_code, country_name)) { - string_printf(display_str, "Reg:%s", string_get_cstr(country_name)); - bank_card_set_country_name(bank_card, string_get_cstr(display_str)); + string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name)); } string_clear(country_name); } - if(emv_data->currency_code) { - string_t currency_name; - string_init(currency_name); - if(nfc_emv_parser_get_currency_name( - nfc->dev->storage, emv_data->country_code, currency_name)) { - string_printf(display_str, "Cur:%s", string_get_cstr(currency_name)); - bank_card_set_currency_name(bank_card, string_get_cstr(display_str)); - } - string_clear(currency_name); - } - string_clear(display_str); + } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + string_set(temp_str, nfc->dev->dev_data.parsed_data); } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); + + widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); + + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); if(event.type == SceneManagerEventTypeCustom) { - if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { - if(nfc->dev->format == NfcDeviceSaveFormatUid) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); - consumed = true; - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - consumed = true; - } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); - consumed = true; - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); - consumed = true; - } - } else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneDeviceInfoData) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); consumed = true; } } @@ -215,12 +78,4 @@ void nfc_scene_device_info_on_exit(void* context) { // Clear views widget_reset(nfc->widget); - if(nfc->dev->format == NfcDeviceSaveFormatUid) { - dialog_ex_reset(nfc->dialog_ex); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - text_box_reset(nfc->text_box); - string_reset(nfc->text_box_store); - } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - bank_card_clear(nfc->bank_card); - } } diff --git a/applications/nfc/scenes/nfc_scene_emv_menu.c b/applications/nfc/scenes/nfc_scene_emv_menu.c new file mode 100644 index 000000000..1da630fcf --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_emv_menu.c @@ -0,0 +1,54 @@ +#include "../nfc_i.h" + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexInfo, +}; + +void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_emv_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_emv_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatBankCard; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneEmvMenu, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_emv_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/nfc/scenes/nfc_scene_emv_read_success.c b/applications/nfc/scenes/nfc_scene_emv_read_success.c index eefe560e3..9cf7ff9e9 100644 --- a/applications/nfc/scenes/nfc_scene_emv_read_success.c +++ b/applications/nfc/scenes/nfc_scene_emv_read_success.c @@ -15,85 +15,48 @@ void nfc_scene_emv_read_success_widget_callback( void nfc_scene_emv_read_success_on_enter(void* context) { Nfc* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup Custom Widget view - // Add frame - widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6); - // Add buttons widget_add_button_element( nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc); - // Add card name - widget_add_string_element( - nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); - // Add card number - string_t pan_str; - string_init(pan_str); + nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc); + + string_t temp_str; + string_init_printf(temp_str, "\e#%s\n", emv_data->name); for(uint8_t i = 0; i < emv_data->number_len; i += 2) { - string_cat_printf(pan_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); + string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); } - string_strim(pan_str); - widget_add_string_element( - nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, string_get_cstr(pan_str)); - string_clear(pan_str); - // Parse country code - string_t country_name; - string_init(country_name); - if((emv_data->country_code) && - nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) { - string_t disp_country; - string_init_printf(disp_country, "Reg:%s", country_name); - widget_add_string_element( - nfc->widget, 7, 23, AlignLeft, AlignTop, FontSecondary, string_get_cstr(disp_country)); - string_clear(disp_country); - } - string_clear(country_name); - // Parse currency code - string_t currency_name; - string_init(currency_name); - if((emv_data->currency_code) && - nfc_emv_parser_get_currency_name( - nfc->dev->storage, emv_data->currency_code, currency_name)) { - string_t disp_currency; - string_init_printf(disp_currency, "Cur:%s", currency_name); - widget_add_string_element( - nfc->widget, - 121, - 23, - AlignRight, - AlignTop, - FontSecondary, - string_get_cstr(disp_currency)); - string_clear(disp_currency); - } - string_clear(currency_name); - char temp_str[32]; - // Add ATQA - snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); - widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str); - // Add UID - snprintf( - temp_str, - sizeof(temp_str), - "UID: %02X %02X %02X %02X", - nfc_data->uid[0], - nfc_data->uid[1], - nfc_data->uid[2], - nfc_data->uid[3]); - widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str); - // Add SAK - snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak); - widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str); + string_strim(temp_str); + // Add expiration date if(emv_data->exp_mon) { - char exp_str[16]; - snprintf( - exp_str, sizeof(exp_str), "Exp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); - widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str); + string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); } + // Parse currency code + if((emv_data->currency_code)) { + string_t currency_name; + string_init(currency_name); + if(nfc_emv_parser_get_currency_name( + nfc->dev->storage, emv_data->currency_code, currency_name)) { + string_cat_printf(temp_str, "\nCur: %s ", string_get_cstr(currency_name)); + } + string_clear(currency_name); + } + // Parse country code + if((emv_data->country_code)) { + string_t country_name; + string_init(country_name); + if(nfc_emv_parser_get_country_name( + nfc->dev->storage, emv_data->country_code, country_name)) { + string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name)); + } + string_clear(country_name); + } + + widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -107,10 +70,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; } else if(event.event == GuiButtonTypeRight) { - // Clear device name - nfc_device_set_name(nfc->dev, ""); - nfc->dev->format = NfcDeviceSaveFormatBankCard; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvMenu); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/nfc/scenes/nfc_scene_file_select.c index 0278c3b9c..693fdec20 100755 --- a/applications/nfc/scenes/nfc_scene_file_select.c +++ b/applications/nfc/scenes/nfc_scene_file_select.c @@ -6,6 +6,7 @@ void nfc_scene_file_select_on_enter(void* context) { // Process file_select return nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); if(nfc_file_select(nfc->dev)) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); } else { scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_info.c b/applications/nfc/scenes/nfc_scene_mf_classic_info.c deleted file mode 100644 index b658dfa48..000000000 --- a/applications/nfc/scenes/nfc_scene_mf_classic_info.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "../nfc_i.h" - -void nfc_scene_mf_classic_info_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - Nfc* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_info_on_enter(void* context) { - Nfc* nfc = context; - NfcDeviceData* dev_data = &nfc->dev->dev_data; - MfClassicData* mf_data = &dev_data->mf_classic_data; - string_t str_tmp; - string_init(str_tmp); - - // Setup view - Widget* widget = nfc->widget; - - widget_add_string_element( - widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type)); - widget_add_string_element( - widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); - string_printf(str_tmp, "UID:"); - for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { - string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); - } - widget_add_string_element( - widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); - string_printf( - str_tmp, - "ATQA: %02X %02X SAK: %02X", - dev_data->nfc_data.atqa[0], - dev_data->nfc_data.atqa[1], - dev_data->nfc_data.sak); - widget_add_string_element( - widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); - uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); - uint8_t keys_total = sectors_total * 2; - uint8_t keys_found = 0; - uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); - string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); - widget_add_string_element( - widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); - string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); - widget_add_string_element( - widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); - - string_clear(str_tmp); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_mf_classic_info_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - widget_reset(nfc->widget); -} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c index 0faa73673..fcb8bc189 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -34,6 +34,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { 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); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c index 6ee0ad868..76d02e01e 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -50,7 +50,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexInfo) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c index bd782305c..efe676706 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -17,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; MfClassicData* mf_data = &dev_data->mf_classic_data; - string_t str_tmp; - string_init(str_tmp); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); @@ -29,48 +27,27 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); + string_t temp_str; if(string_size(nfc->dev->dev_data.parsed_data)) { - widget_add_text_box_element( - nfc->widget, - 0, - 0, - 128, - 32, - AlignLeft, - AlignTop, - string_get_cstr(nfc->dev->dev_data.parsed_data), - true); + string_init_set(temp_str, nfc->dev->dev_data.parsed_data); } else { - widget_add_string_element( - widget, - 0, - 0, - AlignLeft, - AlignTop, - FontSecondary, - mf_classic_get_type_str(mf_data->type)); - widget_add_string_element( - widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); - string_printf(str_tmp, "UID:"); + string_init_printf(temp_str, "\e#%s\n", nfc_mf_classic_type(mf_data->type)); + string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { - string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); + string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); } - widget_add_string_element( - widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); - string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); - widget_add_string_element( - widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); - string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); - widget_add_string_element( - widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); + string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); } - string_clear(str_tmp); + widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c index f15251143..1e2f2d2f2 100644 --- a/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -2,6 +2,8 @@ enum SubmenuIndex { SubmenuIndexSave, + SubmenuIndexEmulateUid, + SubmenuIndexInfo, }; void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { @@ -16,6 +18,15 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) { submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulateUid, + nfc_scene_mf_desfire_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); @@ -35,6 +46,12 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; + } else if(event.event == SubmenuIndexEmulateUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; } } diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c index a04f4e55c..4827c2851 100644 --- a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -1,90 +1,85 @@ #include "../nfc_i.h" #include -#define NFC_SCENE_READ_SUCCESS_SHIFT " " - -enum { - MfDesfireReadSuccessStateShowUID, - MfDesfireReadSuccessStateShowData, -}; - -void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) { +void nfc_scene_mf_desfire_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } } void nfc_scene_mf_desfire_read_success_on_enter(void* context) { Nfc* nfc = context; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_center_button_text(dialog_ex, "Data"); - dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); + Widget* widget = nfc->widget; + + // Prepare string for data display + string_t temp_str; + string_init_printf(temp_str, "\e#MIFARE DESfire\n"); + string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + + uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + string_cat_printf(temp_str, "\n%d", bytes_total); + if(data->version.sw_storage & 1) { + string_push_back(temp_str, '+'); + } + string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free); uint16_t n_apps = 0; uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { n_apps++; for(MifareDesfireFile* file = app->file_head; file; file = file->next) { n_files++; } } + string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + string_push_back(temp_str, 's'); + } + string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + string_push_back(temp_str, 's'); + } - // TODO rework info view - nfc_text_store_set( - nfc, - NFC_SCENE_READ_SUCCESS_SHIFT "Mifare DESFire\n" NFC_SCENE_READ_SUCCESS_SHIFT - "%d%s bytes\n" NFC_SCENE_READ_SUCCESS_SHIFT "%d bytes free\n" - "%d application%s, %d file%s", - 1 << (data->version.sw_storage >> 1), - (data->version.sw_storage & 1) ? "+" : "", - data->free_memory ? data->free_memory->bytes : 0, - n_apps, - n_apps == 1 ? "" : "s", - n_files, - n_files == 1 ? "" : "s"); - dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback); + // Add text scroll element + widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); + // Add button elements + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); if(event.type == SceneManagerEventTypeCustom) { - if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) { + if(event.event == GuiButtonTypeLeft) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; - } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); - consumed = true; - } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) { + } else if(event.event == GuiButtonTypeRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - if(state == MfDesfireReadSuccessStateShowData) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); - scene_manager_set_scene_state( - nfc->scene_manager, - NfcSceneMfDesfireReadSuccess, - MfDesfireReadSuccessStateShowUID); - consumed = true; - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; } return consumed; @@ -94,5 +89,5 @@ void nfc_scene_mf_desfire_read_success_on_exit(void* context) { Nfc* nfc = context; // Clean dialog - dialog_ex_reset(nfc->dialog_ex); + widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c new file mode 100644 index 000000000..d4184a6b4 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c @@ -0,0 +1,32 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_ultralight_data_on_enter(void* context) { + Nfc* nfc = context; + MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; + TextBox* text_box = nfc->text_box; + + text_box_set_font(text_box, TextBoxFontHex); + for(uint16_t i = 0; i < data->data_size; i += 2) { + if(!(i % 8) && i) { + string_push_back(nfc->text_box_store, '\n'); + } + string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]); + } + text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_ultralight_data_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + string_reset(nfc->text_box_store); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 9174a8b19..ba9f22338 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -4,6 +4,7 @@ enum SubmenuIndex { SubmenuIndexUnlock, SubmenuIndexSave, SubmenuIndexEmulate, + SubmenuIndexInfo, }; void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { @@ -33,6 +34,9 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { SubmenuIndexEmulate, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); @@ -56,6 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } else if(event.event == SubmenuIndexUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 65750b963..d775bb71d 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,11 +1,6 @@ #include "../nfc_i.h" #include -enum { - ReadMifareUlStateShowInfo, - ReadMifareUlStateShowData, -}; - void nfc_scene_mf_ultralight_read_success_widget_callback( GuiButtonType result, InputType type, @@ -31,12 +26,6 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { "Retry", nfc_scene_mf_ultralight_read_success_widget_callback, nfc); - widget_add_button_element( - widget, - GuiButtonTypeCenter, - "Data", - nfc_scene_mf_ultralight_read_success_widget_callback, - nfc); widget_add_button_element( widget, GuiButtonTypeRight, @@ -44,71 +33,38 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { nfc_scene_mf_ultralight_read_success_widget_callback, nfc); - widget_add_string_element( - widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); - string_t data_str; - string_init_printf(data_str, "UID:"); + string_t temp_str; + string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); + string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < data->uid_len; i++) { - string_cat_printf(data_str, " %02X", data->uid[i]); + string_cat_printf(temp_str, " %02X", data->uid[i]); } - widget_add_string_element( - widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); - string_printf( - data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); - widget_add_string_element( - widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); + string_cat_printf( + temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); if(mf_ul_data->data_read != mf_ul_data->data_size) { - widget_add_string_element( - widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!"); + string_cat_printf(temp_str, "\nPassword-protected pages!"); } - string_clear(data_str); + widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); - // Setup TextBox view - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { - if(!(i % 8) && i) { - string_push_back(nfc->text_box_store, '\n'); - } - string_cat_printf( - nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); - } - text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); - - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); if(event.type == SceneManagerEventTypeCustom) { - if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { + if(event.event == GuiButtonTypeLeft) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; - } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { + } else if(event.event == GuiButtonTypeRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); consumed = true; - } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); - consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - if(state == ReadMifareUlStateShowData) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); - consumed = true; - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; } return consumed; @@ -117,8 +73,6 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { Nfc* nfc = context; - // Clean views + // Clean view widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - string_reset(nfc->text_box_store); } diff --git a/applications/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/nfc/scenes/nfc_scene_nfc_data_info.c new file mode 100644 index 000000000..33f5e44af --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfc_data_info.c @@ -0,0 +1,133 @@ +#include "../nfc_i.h" + +void nfc_scene_nfc_data_info_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_nfc_data_info_on_enter(void* context) { + Nfc* nfc = context; + Widget* widget = nfc->widget; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + NfcProtocol protocol = dev_data->protocol; + uint8_t text_scroll_height = 0; + if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) { + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); + text_scroll_height = 52; + } else { + text_scroll_height = 64; + } + + string_t temp_str; + string_init(temp_str); + // Set name if present + if(nfc->dev->dev_name[0] != '\0') { + string_printf(temp_str, "\ec%s\n", nfc->dev->dev_name); + } + + // Set tag type + if(protocol == NfcDeviceProtocolEMV) { + string_cat_printf(temp_str, "\e#EMV Bank Card\n"); + } else if(protocol == NfcDeviceProtocolMifareUl) { + string_cat_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true)); + } else if(protocol == NfcDeviceProtocolMifareClassic) { + string_cat_printf( + temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); + } else if(protocol == NfcDeviceProtocolMifareDesfire) { + string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + } else { + string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); + } + + // Set tag iso data + char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; + string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); + string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); + + // Set application specific data + if(protocol == NfcDeviceProtocolMifareDesfire) { + MifareDesfireData* data = &dev_data->mf_df_data; + uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + string_cat_printf(temp_str, "\n%d", bytes_total); + if(data->version.sw_storage & 1) { + string_push_back(temp_str, '+'); + } + string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + string_push_back(temp_str, 's'); + } + string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + string_push_back(temp_str, 's'); + } + } else if(protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* data = &dev_data->mf_ul_data; + string_cat_printf( + temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4); + if(data->data_size > data->data_read) { + string_cat_printf(temp_str, "\nPassword-protected"); + } + } else if(protocol == NfcDeviceProtocolMifareClassic) { + MfClassicData* data = &dev_data->mf_classic_data; + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); + string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); + } + + // Add text scroll widget + widget_add_text_scroll_element( + widget, 0, 0, 128, text_scroll_height, string_get_cstr(temp_str)); + string_clear(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcProtocol protocol = nfc->dev->dev_data.protocol; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + if(protocol == NfcDeviceProtocolMifareDesfire) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); + consumed = true; + } else if(protocol == NfcDeviceProtocolMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_nfc_data_info_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_nfca_menu.c b/applications/nfc/scenes/nfc_scene_nfca_menu.c new file mode 100644 index 000000000..00d0d943d --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfca_menu.c @@ -0,0 +1,62 @@ +#include "../nfc_i.h" + +enum SubmenuIndex { + SubmenuIndexSaveUid, + SubmenuIndexEmulateUid, + SubmenuIndexInfo, +}; + +void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfca_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save UID", SubmenuIndexSaveUid, nfc_scene_nfca_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate UID", SubmenuIndexEmulateUid, nfc_scene_nfca_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfca_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSaveUid) { + nfc->dev->format = NfcDeviceSaveFormatUid; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulateUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfca_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/nfc/scenes/nfc_scene_nfca_read_success.c new file mode 100644 index 000000000..3467a03b6 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfca_read_success.c @@ -0,0 +1,72 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_nfca_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Nfc* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfca_read_success_on_enter(void* context) { + Nfc* nfc = context; + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Setup view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + + string_t temp_str; + string_init_set_str(temp_str, "\e#Unknown ISO tag\n"); + + char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3'; + string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", data->uid[i]); + } + string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); + string_cat_printf(temp_str, " SAK: %02X", data->sak); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); + string_clear(temp_str); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfca_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfca_read_success_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_nfca_read_success_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_read.c b/applications/nfc/scenes/nfc_scene_read.c index 491b419ef..00b7c8fac 100644 --- a/applications/nfc/scenes/nfc_scene_read.c +++ b/applications/nfc/scenes/nfc_scene_read.c @@ -59,11 +59,14 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if((event.event == NfcWorkerEventReadUidNfcB) || (event.event == NfcWorkerEventReadUidNfcF) || - (event.event == NfcWorkerEventReadUidNfcV) || - (event.event == NfcWorkerEventReadUidNfcA)) { + (event.event == NfcWorkerEventReadUidNfcV)) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); consumed = true; + } else if(event.event == NfcWorkerEventReadUidNfcA) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); + consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index b889ce08d..0cb38cbdf 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -16,44 +16,26 @@ void nfc_scene_read_card_success_widget_callback( void nfc_scene_read_card_success_on_enter(void* context) { Nfc* nfc = context; - string_t data_str; - string_t uid_str; - string_init(data_str); - string_init(uid_str); + string_t temp_str; + string_init(temp_str); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; - string_set_str(data_str, nfc_get_dev_type(data->type)); - string_set_str(uid_str, "UID:"); + string_set_str(temp_str, nfc_get_dev_type(data->type)); + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(temp_str)); + string_set_str(temp_str, "UID:"); for(uint8_t i = 0; i < data->uid_len; i++) { - string_cat_printf(uid_str, " %02X", data->uid[i]); + string_cat_printf(temp_str, " %02X", data->uid[i]); } - + widget_add_string_element( + widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(temp_str)); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); - if(data->type == FuriHalNfcTypeA) { - widget_add_button_element( - widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc); - widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); - widget_add_string_element( - widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str)); - string_printf( - data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak); - widget_add_string_multiline_element( - widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); - widget_add_string_element( - widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, string_get_cstr(uid_str)); - } else { - widget_add_string_element( - widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(data_str)); - widget_add_string_element( - widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(uid_str)); - } - string_clear(data_str); - string_clear(uid_str); + string_clear(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -65,11 +47,6 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(event.event == GuiButtonTypeRight) { - nfc->dev->format = NfcDeviceSaveFormatUid; - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; } } return consumed; diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index e6b08e71b..c7aec5d87 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -44,8 +44,6 @@ void nfc_scene_saved_menu_on_enter(void* context) { } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); if(nfc->dev->shadow_file_exist) { submenu_add_item( submenu, @@ -58,12 +56,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); submenu_add_item( submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +88,18 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); + bool application_info_present = false; + if(dev_data->protocol == NfcDeviceProtocolEMV) { + application_info_present = true; + } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + application_info_present = nfc_supported_card_verify_and_parse(dev_data); + } + + if(application_info_present) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + } consumed = true; } else if(event.event == SubmenuIndexRestoreOriginal) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); diff --git a/applications/nfc/views/bank_card.c b/applications/nfc/views/bank_card.c deleted file mode 100755 index 31cc56ee8..000000000 --- a/applications/nfc/views/bank_card.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "bank_card.h" -#include "../helpers/nfc_emv_parser.h" -#include - -struct BankCard { - Widget* widget; -}; - -BankCard* bank_card_alloc() { - BankCard* bank_card = malloc(sizeof(BankCard)); - bank_card->widget = widget_alloc(); - return bank_card; -} - -void bank_card_free(BankCard* bank_card) { - furi_assert(bank_card); - widget_free(bank_card->widget); - free(bank_card); -} - -View* bank_card_get_view(BankCard* bank_card) { - furi_assert(bank_card); - return widget_get_view(bank_card->widget); -} - -void bank_card_clear(BankCard* bank_card) { - furi_assert(bank_card); - widget_reset(bank_card->widget); -} - -void bank_card_set_name(BankCard* bank_card, char* name) { - furi_assert(bank_card); - furi_assert(name); - widget_add_string_element( - bank_card->widget, 64, 6, AlignCenter, AlignTop, FontSecondary, name); -} - -void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len) { - furi_assert(bank_card); - furi_assert(number); - string_t num_str; - string_init(num_str); - for(uint8_t i = 0; i < len; i += 2) { - string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]); - } - // Add number - widget_add_string_element( - bank_card->widget, 64, 32, AlignCenter, AlignTop, FontSecondary, string_get_cstr(num_str)); - string_clear(num_str); - // Add icon - widget_add_icon_element(bank_card->widget, 8, 15, &I_Detailed_chip_17x13); - // Add frame - widget_add_frame_element(bank_card->widget, 0, 0, 128, 64, 6); -} - -void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context) { - furi_assert(bank_card); - furi_assert(callback); - widget_add_button_element(bank_card->widget, GuiButtonTypeLeft, "Back", callback, context); -} - -void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { - furi_assert(bank_card); - char exp_date_str[16]; - snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02X/%02X", mon, year); - widget_add_string_element( - bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); -} - -void bank_card_set_country_name(BankCard* bank_card, const char* country_name) { - furi_assert(bank_card); - widget_add_string_element( - bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name); -} - -void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) { - furi_assert(bank_card); - widget_add_string_element( - bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name); -} diff --git a/applications/nfc/views/bank_card.h b/applications/nfc/views/bank_card.h deleted file mode 100644 index 628d9deb8..000000000 --- a/applications/nfc/views/bank_card.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -typedef struct BankCard BankCard; - -BankCard* bank_card_alloc(); - -void bank_card_free(BankCard* bank_card); - -void bank_card_clear(BankCard* bank_card); - -View* bank_card_get_view(BankCard* bank_card); - -void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context); - -void bank_card_set_name(BankCard* bank_card, char* name); - -void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len); - -void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); - -void bank_card_set_country_name(BankCard* bank_card, const char* country_name); - -void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name); diff --git a/assets/icons/NFC/Keychain.png b/assets/icons/NFC/Keychain.png new file mode 100644 index 0000000000000000000000000000000000000000..7ba1b11da6fde4e2b4b148a35593937f2a2ac471 GIT binary patch literal 3750 zcmaJ@c{r5&+kYIguVo48j3ryln6WiupT!bG7#T?!j3JE~V`?lVlr0^Soruc5Bx-6b zWy_KfqU;Gt4o;RR;T`99I=}aixA(c8=lOoW_jP|h_vc=o>w4l&*jfnj%kTpLAY^5U zc3`h6>_>x_ll|_iwQmIgevB^)b;1gT0#RucZ{PDo00u!Mb+7zV>7+mRQ`nUD~EL&9D|@H+oHo*DVO30LpM zUVphY6?)HasD9&P_s-+D#&hMXIW@gJjl6?q}5i}sc3p8T08?_F_?23FwW}fBPdaAJ8!ir* zh9n>h0aJ61@SF@~M<9<2aPRW;m=6~H26zPlE&JFgHGnG=aPLr53<9oY z0^;T?&W2x(R*KH4vn!QZZOBrBVIbsHOlgMGx!S(SX#*gd1>& zlXvbOS>p0JBanAtBi_4O#Pl(cH$URMO5LjsCjTaDczAYZ=H2mDq$}a2^W_~<^Vvq{ z?epKl41a8_zkl{YDFWseVZpWezWLRfO~IkwTYT3%#y%!m{CFa;`$KL(q1DQRg;y7! zw%;F+fX=$H3M){EL*7z*aio9O>%*kR7N_x~E>LyOm?Jbvv)Ij(^Q*OrD4yQL^WbRCzhWeXdURGIp0uwk`6G0O8(Nw*mm*3|a|{ds$=B&Ih6#?rgA!s_CC?cRAF$l(^Fw1 zs>pW&Z*G%neFPtuSqJX{g8WD2WcTAi`lYOS}!<_MK%h=#Y|**a)9KALljuW)+3xV(UlBwPN2|4|>3$ zF?dT2#i9L)2Oy%Mv8YykrTuXzm)WD9&q?Wb0VUC?;U#t;;Wmbls;OH!52KFD*BB+WSZAj76mdLUl99jB!aUC5Zr6v?DG;nkVymn4#2 z@~0k8RZf*vhu}&|3ri6T5MYEQ1|Wg9-f`9ZvzQ5QJ$&h+dR@l0 zTwT0TX-PgDrF~r6xyE5N#oL5uIwN57HrtdQ|4BdSGLA}#x7+! zU|EG~g$6bTHtpT7y6<)mW$I=dLEpmWvgfkjW=}qGKNWOJgIUacO0=q;IaTPg#H{y^ zIt6zrz&o9Ct1++0sW>uJS5a3aR>ZPRwk^vYBDGX~VRkZ0o=8{CzT+OPWRjVe2_z3G z(vugJElbG_$(L&{|FLbvBNQ_%Tqbu)E-dg7O&oC&F_G1Cd&%VTi?y_Q2npXS+WSs> znt7m0t<^WjF?+y*Bt>EcUR{likF$>K0;d~;vt`@HI~rz=)7Jysrb7DHbFyo)n-_~m zA1vuD`7Xtb-Fc;RM=jSyJMeW&2kO23Y@dn1om4Hq$?`BelwAbr@th*W6O!ay@wVzo z0i$$-uqu+0|A(!NzCzv2ciC?RS7tL zBJ9)9YaYT!LVQb@ph{FslykI60yP#d(+5r0W%P}q0w>Ym(P`+3Y!cKC{y_7%uDWq4 z_?+R0eyvWeNgLSP<<%fQ2XA%W`VbtfUa9AQ{@LV@#nqS(IUfY3L!~kx9d6X%{GR5u zs3OS{@O}+MnyF2!?Xi@<%tY0TC2t&AIlwrQz#rT!*Gy7?^y&4*zC)c>KWw{Vsg4b~ z^=DGOZm`k|?E;Ni)-{!qoAowAHsjfdT*<79ATrDd(Ez=AE9qtcvQ!?M%p`p#ee}NA zRZfhm-g)64{{(V4m8a9M=4Sam7fpU9vhWk`l`S?@LLdY;-8JWyfF55(ajDIahZHf_#T}jYb+6Wy;6KsDqZ5r zJJqqES=kuM%jcP6DUV9ZT3KGb-u>S5A15?(U4_$1(?6yQ`wI<^JQA8b`Dk(dD`pgu z-mN-Xca@1^-Ft5Mw4PYh+0$)cg1e7f!+po;E%lE-CcNGB?^}`$t^ca?=isPo{l>O& z=d)2K4kzrO_aJf0YO7|$q%y8_elu;0>{ek*4p?mG?C0F(Q50srWxW}c>o>wVBn};2 zun=zl{n<{=GDA~HPsr(y+if2dsp#OD`3=6wjl)8Sk&8D%%cpn-e!nP3l7pN>X02qI zXFFzXxq7(P+PyOF8~QvE^21{EcahsVhAzR!S8<)bBlD31$)uIu8#$>tm&3r{#@t8m zGDGJ)dnV6`P?l>&=~Mlf-S|0!dV`+RD^KYw)uXcqoS!;pJwTi#f2Myn+({m=Yp=Uq zmsQC+?Z;XQX?Ps!y)iGFtKT!e))4$fa(8Gj7j87(uo^&0GRqQQh_V_HfK?pVhnMfyqg2?Cn0}(++3V-t=*!w**L;>`-3*FC1;Xk7A*b^WWg+>JF zgQ1$9T3T8leK?rtMSyu|dlNi0Krk&B6ar=6`kGLE1WX$Ng@gXN6xac2Ufu`?wD~{b z*e4?eA3B|ifIt`w2AH7@rqD#!lXu%*bm?qmpGceenP6*QU4^;fgfF=fd(tN3O zUy46ykCEU(xj;8kV2k}v7G&zbwEltrREk|QNDzSvfr7R6vij+W#s2@UWb(h>fpiDr zfA#*K#DTbADiPv945VD3d9r)wt+*G8ia^nb1UiL=qfpNOEaV9v3Y`+@L!p9T+F&S1 z6-)5+_209o{SCol5mx?zbb`Mp(F$#(z$O9v`g$Ss%rQ{yW6)z-x|m~7CjrXGG2U~bFwXi~nObWxEF+N1LG)vAL*y4V znZdc7@J&n`SL#XXY9}k7)0r8V0;wPHVQ>|=|K$#i_yQ>PR>QbidiqjLu%1ovk{e`n zvwDI75yjixLswvHKnnpN;w1fRT6NKTL0;1J>92DXdev_data); dev->format = NfcDeviceSaveFormatUid; string_reset(dev->load_path); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index a92f148a2..45bbc5f41 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -143,7 +143,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { read_success = true; - nfc_supported_card[i].parse(nfc_worker); + nfc_supported_card[i].parse(nfc_worker->dev_data); } } } diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c index 59482a123..480c970e7 100644 --- a/lib/nfc/parsers/nfc_supported_card.c +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -11,3 +11,17 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { .parse = troyka_parser_parse, }, }; + +bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { + furi_assert(dev_data); + + bool card_parsed = false; + for(size_t i = 0; i < COUNT_OF(nfc_supported_card); i++) { + if(nfc_supported_card[i].parse(dev_data)) { + card_parsed = true; + break; + } + } + + return card_parsed; +} diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/parsers/nfc_supported_card.h index 5c94c78cd..9b5d1c053 100644 --- a/lib/nfc/parsers/nfc_supported_card.h +++ b/lib/nfc/parsers/nfc_supported_card.h @@ -2,6 +2,7 @@ #include #include "../nfc_worker.h" +#include "../nfc_device.h" #include @@ -15,7 +16,7 @@ typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxCont typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -typedef bool (*NfcSupportedCardParse)(NfcWorker* nfc_worker); +typedef bool (*NfcSupportedCardParse)(NfcDeviceData* dev_data); typedef struct { NfcProtocol protocol; @@ -25,3 +26,5 @@ typedef struct { } NfcSupportedCard; extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; + +bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/parsers/troyka_parser.c b/lib/nfc/parsers/troyka_parser.c index 3167b5181..51ffa42e1 100644 --- a/lib/nfc/parsers/troyka_parser.c +++ b/lib/nfc/parsers/troyka_parser.c @@ -49,23 +49,31 @@ bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; } -bool troyka_parser_parse(NfcWorker* nfc_worker) { - MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; - uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; - uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; - temp_ptr = &data->block[8 * 4].value[3]; - uint32_t number = 0; - for(size_t i = 0; i < 4; i++) { - number <<= 8; - number |= temp_ptr[i]; - } - number >>= 4; +bool troyka_parser_parse(NfcDeviceData* dev_data) { + MfClassicData* data = &dev_data->mf_classic_data; + bool troyka_parsed = false; - string_printf( - nfc_worker->dev_data->parsed_data, - "Troyka Transport card\nNumber: %ld\nBalance: %d rub", - number, - balance); + do { + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(key != troyka_keys[8].key_a) break; - return true; + // Parse data + uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; + uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; + temp_ptr = &data->block[8 * 4].value[3]; + uint32_t number = 0; + for(size_t i = 0; i < 4; i++) { + number <<= 8; + number |= temp_ptr[i]; + } + number >>= 4; + + string_printf( + dev_data->parsed_data, "\e#Troyka\nNum: %ld\nBalance: %d rur.", number, balance); + troyka_parsed = true; + } while(false); + + return troyka_parsed; } diff --git a/lib/nfc/parsers/troyka_parser.h b/lib/nfc/parsers/troyka_parser.h index 0d5cee233..445fe40e5 100644 --- a/lib/nfc/parsers/troyka_parser.h +++ b/lib/nfc/parsers/troyka_parser.h @@ -6,4 +6,4 @@ bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool troyka_parser_parse(NfcWorker* nfc_worker); +bool troyka_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index c043f2069..f637d378a 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -191,7 +191,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint } if(pack != NULL) { - *pack = (tx_rx->rx_data[0] << 8) | tx_rx->rx_data[1]; + *pack = (tx_rx->rx_data[1] << 8) | tx_rx->rx_data[0]; } FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack); @@ -697,48 +697,6 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* return counter_read == (is_single_counter ? 1 : 3); } -int16_t mf_ultralight_get_authlim( - FuriHalNfcTxRxContext* tx_rx, - MfUltralightReader* reader, - MfUltralightData* data) { - mf_ultralight_read_version(tx_rx, reader, data); - if(!(reader->supported_features & MfUltralightSupportAuth)) { - // No authentication - return -2; - } - - uint8_t config_pages_index; - if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { - config_pages_index = reader->pages_to_read - 4; - } else if( - data->type >= MfUltralightTypeNTAGI2CPlus1K && - data->type <= MfUltralightTypeNTAGI2CPlus1K) { - config_pages_index = 0xe3; - } else { - // No config pages - return -2; - } - - if(!mf_ultralight_read_pages_direct(tx_rx, config_pages_index, data->data)) { - // Config pages are not readable due to protection - return -1; - } - - MfUltralightConfigPages* config_pages = (MfUltralightConfigPages*)&data->data; - if(config_pages->auth0 >= reader->pages_to_read) { - // Authentication is not configured - return -2; - } - - int16_t authlim = config_pages->access.authlim; - if(authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K && - data->type <= MfUltralightTypeNTAGI2CPlus2K) { - authlim = 1 << authlim; - } - - return authlim; -} - bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { uint8_t flag_read = 0; diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 727bffab2..9642824f7 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -56,13 +56,6 @@ typedef enum { MfUltralightTypeNum, } MfUltralightType; -typedef enum { - MfUltralightAuthLimitUnknown, - MfUltralightAuthLimitNotSupported, - MfUltralightAuthLimitConfigured, - MfUltralightAuthLimitNotConfigured, -} MfUltralightAuthLimit; - typedef enum { MfUltralightSupportNone = 0, MfUltralightSupportFastRead = 1 << 0, @@ -245,11 +238,6 @@ bool mf_ul_prepare_emulation_response( uint32_t* data_type, void* context); -int16_t mf_ultralight_get_authlim( - FuriHalNfcTxRxContext* tx_rx, - MfUltralightReader* reader, - MfUltralightData* data); - uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data); uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data);