NFC Unit tests part 1.1 (#1927)
* Mifare Classic 1/4K, 4/7b uid, NFC-A: NFC-A is not complete yet, as there are no 4b uid tests. Also, Mifare Classic tests don't cover the key cache yet. * NFC unit tests require access to the NFC app * Made nfc_device_save accept full path as an argument * Move from cstrs to furi strings and fix logic * nfc tests: fix memory leak * nfc: add mf_classic_get_total_blocks() to API * nfc tests: simplify nfc tests * nfc: fix memory leak in shadow file saving * nfc: fix set uid scene * nfc: fix saving files * nfc: fix preload nfc file path * nfc: remove comments Co-authored-by: Sergey Gavrilov <who.just.the.doctor@gmail.com> Co-authored-by: gornekich <n.gorbadey@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									a66e8d9ac9
								
							
						
					
					
						commit
						820afd2aec
					
				| @ -5,6 +5,8 @@ | |||||||
| #include <lib/nfc/protocols/nfca.h> | #include <lib/nfc/protocols/nfca.h> | ||||||
| #include <lib/nfc/helpers/mf_classic_dict.h> | #include <lib/nfc/helpers/mf_classic_dict.h> | ||||||
| #include <lib/digital_signal/digital_signal.h> | #include <lib/digital_signal/digital_signal.h> | ||||||
|  | #include <lib/nfc/nfc_device.h> | ||||||
|  | #include <applications/main/nfc/helpers/nfc_generators.h> | ||||||
| 
 | 
 | ||||||
| #include <lib/flipper_format/flipper_format_i.h> | #include <lib/flipper_format/flipper_format_i.h> | ||||||
| #include <lib/toolbox/stream/file_stream.h> | #include <lib/toolbox/stream/file_stream.h> | ||||||
| @ -17,6 +19,7 @@ | |||||||
| #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" | #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" | ||||||
| #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" | #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" | ||||||
| #define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") | #define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") | ||||||
|  | #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc") | ||||||
| 
 | 
 | ||||||
| static const char* nfc_test_file_type = "Flipper NFC test"; | static const char* nfc_test_file_type = "Flipper NFC test"; | ||||||
| static const uint32_t nfc_test_file_version = 1; | static const uint32_t nfc_test_file_version = 1; | ||||||
| @ -287,9 +290,203 @@ MU_TEST(mf_classic_dict_load_test) { | |||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | MU_TEST(nfca_file_test) { | ||||||
|  |     NfcDevice* nfc = nfc_device_alloc(); | ||||||
|  |     mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n"); | ||||||
|  |     nfc->format = NfcDeviceSaveFormatUid; | ||||||
|  | 
 | ||||||
|  |     // Fill the UID, sak, ATQA and type
 | ||||||
|  |     uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00}; | ||||||
|  |     memcpy(nfc->dev_data.nfc_data.uid, uid, 7); | ||||||
|  |     nfc->dev_data.nfc_data.uid_len = 7; | ||||||
|  | 
 | ||||||
|  |     nfc->dev_data.nfc_data.sak = 0x08; | ||||||
|  |     nfc->dev_data.nfc_data.atqa[0] = 0x00; | ||||||
|  |     nfc->dev_data.nfc_data.atqa[1] = 0x04; | ||||||
|  |     nfc->dev_data.nfc_data.type = FuriHalNfcTypeA; | ||||||
|  | 
 | ||||||
|  |     // Save the NFC device data to the file
 | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n"); | ||||||
|  |     nfc_device_free(nfc); | ||||||
|  | 
 | ||||||
|  |     // Load the NFC device data from the file
 | ||||||
|  |     NfcDevice* nfc_validate = nfc_device_alloc(); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true), | ||||||
|  |         "nfc_device_load == true assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Check the UID, sak, ATQA and type
 | ||||||
|  |     mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n"); | ||||||
|  |     mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, | ||||||
|  |         "type == FuriHalNfcTypeA assert failed\r\n"); | ||||||
|  |     nfc_device_free(nfc_validate); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { | ||||||
|  |     NfcDevice* nfc_dev = nfc_device_alloc(); | ||||||
|  |     mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n"); | ||||||
|  |     nfc_dev->format = NfcDeviceSaveFormatMifareClassic; | ||||||
|  | 
 | ||||||
|  |     // Create a test file
 | ||||||
|  |     nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type); | ||||||
|  | 
 | ||||||
|  |     // Get the uid from generated MFC
 | ||||||
|  |     uint8_t uid[7] = {0}; | ||||||
|  |     memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len); | ||||||
|  |     uint8_t sak = nfc_dev->dev_data.nfc_data.sak; | ||||||
|  |     uint8_t atqa[2] = {}; | ||||||
|  |     memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2); | ||||||
|  | 
 | ||||||
|  |     MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data; | ||||||
|  |     // Check the manufacturer block (should be uid[uid_len] + 0xFF[rest])
 | ||||||
|  |     uint8_t manufacturer_block[16] = {0}; | ||||||
|  |     memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16); | ||||||
|  |     mu_assert( | ||||||
|  |         memcmp(manufacturer_block, uid, uid_len) == 0, | ||||||
|  |         "manufacturer_block uid doesn't match the file\r\n"); | ||||||
|  |     for(uint8_t i = uid_len; i < 16; i++) { | ||||||
|  |         mu_assert( | ||||||
|  |             manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6])
 | ||||||
|  |     uint8_t sector_trailer[16] = { | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0x07, | ||||||
|  |         0x80, | ||||||
|  |         0x69, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF, | ||||||
|  |         0xFF}; | ||||||
|  |     // Reference block data
 | ||||||
|  |     uint8_t block_data[16] = {}; | ||||||
|  |     memset(block_data, 0xff, sizeof(block_data)); | ||||||
|  |     uint16_t total_blocks = mf_classic_get_total_block_num(type); | ||||||
|  |     for(size_t i = 1; i < total_blocks; i++) { | ||||||
|  |         if(mf_classic_is_sector_trailer(i)) { | ||||||
|  |             mu_assert( | ||||||
|  |                 memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, | ||||||
|  |                 "Failed sector trailer compare"); | ||||||
|  |         } else { | ||||||
|  |             mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Save the NFC device data to the file
 | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH), | ||||||
|  |         "nfc_device_save == true assert failed\r\n"); | ||||||
|  |     // Verify that key cache is saved
 | ||||||
|  |     FuriString* key_cache_name = furi_string_alloc(); | ||||||
|  |     furi_string_set_str(key_cache_name, "/ext/nfc/cache/"); | ||||||
|  |     for(size_t i = 0; i < uid_len; i++) { | ||||||
|  |         furi_string_cat_printf(key_cache_name, "%02X", uid[i]); | ||||||
|  |     } | ||||||
|  |     furi_string_cat_printf(key_cache_name, ".keys"); | ||||||
|  |     mu_assert( | ||||||
|  |         storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) == | ||||||
|  |             FSE_OK, | ||||||
|  |         "Key cache file save failed"); | ||||||
|  |     nfc_device_free(nfc_dev); | ||||||
|  | 
 | ||||||
|  |     // Load the NFC device data from the file
 | ||||||
|  |     NfcDevice* nfc_validate = nfc_device_alloc(); | ||||||
|  |     mu_assert(nfc_validate, "Nfc device alloc assert"); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false), | ||||||
|  |         "nfc_device_load == true assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Check the UID, sak, ATQA and type
 | ||||||
|  |     mu_assert( | ||||||
|  |         memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0, | ||||||
|  |         "uid compare assert failed\r\n"); | ||||||
|  |     mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0, | ||||||
|  |         "atqa compare assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, | ||||||
|  |         "type == FuriHalNfcTypeA assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Check the manufacturer block
 | ||||||
|  |     mu_assert( | ||||||
|  |         memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0, | ||||||
|  |         "manufacturer_block assert failed\r\n"); | ||||||
|  |     // Check other blocks
 | ||||||
|  |     for(size_t i = 1; i < total_blocks; i++) { | ||||||
|  |         if(mf_classic_is_sector_trailer(i)) { | ||||||
|  |             mu_assert( | ||||||
|  |                 memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, | ||||||
|  |                 "Failed sector trailer compare"); | ||||||
|  |         } else { | ||||||
|  |             mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     nfc_device_free(nfc_validate); | ||||||
|  | 
 | ||||||
|  |     // Check saved key cache
 | ||||||
|  |     NfcDevice* nfc_keys = nfc_device_alloc(); | ||||||
|  |     mu_assert(nfc_validate, "Nfc device alloc assert"); | ||||||
|  |     nfc_keys->dev_data.nfc_data.uid_len = uid_len; | ||||||
|  |     memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); | ||||||
|  |     mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); | ||||||
|  |     uint8_t total_sec = mf_classic_get_total_sectors_num(type); | ||||||
|  |     uint8_t default_key[6] = {}; | ||||||
|  |     memset(default_key, 0xff, 6); | ||||||
|  |     for(size_t i = 0; i < total_sec; i++) { | ||||||
|  |         MfClassicSectorTrailer* sec_tr = | ||||||
|  |             mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); | ||||||
|  |         mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); | ||||||
|  |         mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Delete key cache file
 | ||||||
|  |     mu_assert( | ||||||
|  |         storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK, | ||||||
|  |         "Failed to remove key cache file"); | ||||||
|  |     furi_string_free(key_cache_name); | ||||||
|  |     nfc_device_free(nfc_keys); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mf_classic_1k_4b_file_test) { | ||||||
|  |     mf_classic_generator_test(4, MfClassicType1k); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mf_classic_4k_4b_file_test) { | ||||||
|  |     mf_classic_generator_test(4, MfClassicType4k); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mf_classic_1k_7b_file_test) { | ||||||
|  |     mf_classic_generator_test(7, MfClassicType1k); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mf_classic_4k_7b_file_test) { | ||||||
|  |     mf_classic_generator_test(7, MfClassicType4k); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| MU_TEST_SUITE(nfc) { | MU_TEST_SUITE(nfc) { | ||||||
|     nfc_test_alloc(); |     nfc_test_alloc(); | ||||||
| 
 | 
 | ||||||
|  |     MU_RUN_TEST(nfca_file_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_1k_4b_file_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_4k_4b_file_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_1k_7b_file_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_4k_7b_file_test); | ||||||
|     MU_RUN_TEST(nfc_digital_signal_test); |     MU_RUN_TEST(nfc_digital_signal_test); | ||||||
|     MU_RUN_TEST(mf_classic_dict_test); |     MU_RUN_TEST(mf_classic_dict_test); | ||||||
|     MU_RUN_TEST(mf_classic_dict_load_test); |     MU_RUN_TEST(mf_classic_dict_load_test); | ||||||
|  | |||||||
| @ -314,7 +314,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { | |||||||
|     mful->version.storage_size = 0x15; |     mful->version.storage_size = 0x15; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { | void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { | ||||||
|     nfc_generate_common_start(data); |     nfc_generate_common_start(data); | ||||||
|     nfc_generate_mf_classic_common(data, uid_len, type); |     nfc_generate_mf_classic_common(data, uid_len, type); | ||||||
| 
 | 
 | ||||||
| @ -337,6 +337,9 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas | |||||||
|             } |             } | ||||||
|             mf_classic_set_block_read(mfc, i, &mfc->block[i]); |             mf_classic_set_block_read(mfc, i, &mfc->block[i]); | ||||||
|         } |         } | ||||||
|  |         // Set SAK to 18
 | ||||||
|  |         data->nfc_data.sak = 0x18; | ||||||
|  | 
 | ||||||
|     } else if(type == MfClassicType1k) { |     } else if(type == MfClassicType1k) { | ||||||
|         // Set every block to 0xFF
 |         // Set every block to 0xFF
 | ||||||
|         for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { |         for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { | ||||||
| @ -347,6 +350,8 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas | |||||||
|             } |             } | ||||||
|             mf_classic_set_block_read(mfc, i, &mfc->block[i]); |             mf_classic_set_block_read(mfc, i, &mfc->block[i]); | ||||||
|         } |         } | ||||||
|  |         // Set SAK to 08
 | ||||||
|  |         data->nfc_data.sak = 0x08; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     mfc->type = type; |     mfc->type = type; | ||||||
|  | |||||||
| @ -11,3 +11,5 @@ struct NfcGenerator { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern const NfcGenerator* const nfc_generators[]; | extern const NfcGenerator* const nfc_generators[]; | ||||||
|  | 
 | ||||||
|  | void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type); | ||||||
|  | |||||||
| @ -116,7 +116,9 @@ void nfc_free(Nfc* nfc) { | |||||||
|         // Stop worker
 |         // Stop worker
 | ||||||
|         nfc_worker_stop(nfc->worker); |         nfc_worker_stop(nfc->worker); | ||||||
|         // Save data in shadow file
 |         // Save data in shadow file
 | ||||||
|         nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); |         if(furi_string_size(nfc->dev->load_path)) { | ||||||
|  |             nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     if(nfc->rpc_ctx) { |     if(nfc->rpc_ctx) { | ||||||
|         rpc_system_app_send_exited(nfc->rpc_ctx); |         rpc_system_app_send_exited(nfc->rpc_ctx); | ||||||
| @ -218,6 +220,13 @@ void nfc_blink_stop(Nfc* nfc) { | |||||||
|     notification_message(nfc->notifications, &sequence_blink_stop); |     notification_message(nfc->notifications, &sequence_blink_stop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool nfc_save_file(Nfc* nfc) { | ||||||
|  |     furi_string_printf( | ||||||
|  |         nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); | ||||||
|  |     bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); | ||||||
|  |     return file_saved; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void nfc_show_loading_popup(void* context, bool show) { | void nfc_show_loading_popup(void* context, bool show) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); |     TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); | ||||||
|  | |||||||
| @ -114,4 +114,6 @@ void nfc_blink_detect_start(Nfc* nfc); | |||||||
| 
 | 
 | ||||||
| void nfc_blink_stop(Nfc* nfc); | void nfc_blink_stop(Nfc* nfc); | ||||||
| 
 | 
 | ||||||
|  | bool nfc_save_file(Nfc* nfc); | ||||||
|  | 
 | ||||||
| void nfc_show_loading_popup(void* context, bool show); | void nfc_show_loading_popup(void* context, bool show); | ||||||
|  | |||||||
| @ -5,6 +5,9 @@ void nfc_scene_file_select_on_enter(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     // Process file_select return
 |     // Process file_select return
 | ||||||
|     nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); |     nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); | ||||||
|  |     if(!furi_string_size(nfc->dev->load_path)) { | ||||||
|  |         furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER); | ||||||
|  |     } | ||||||
|     if(nfc_file_select(nfc->dev)) { |     if(nfc_file_select(nfc->dev)) { | ||||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); | ||||||
|  | |||||||
| @ -48,7 +48,10 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even | |||||||
|            NFC_MF_CLASSIC_DATA_CHANGED) { |            NFC_MF_CLASSIC_DATA_CHANGED) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); |                 nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); | ||||||
|             nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); |             // Save shadow file
 | ||||||
|  |             if(furi_string_size(nfc->dev->load_path)) { | ||||||
|  |                 nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         consumed = false; |         consumed = false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -57,7 +57,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcWorkerEventSuccess) { |         if(event.event == NfcWorkerEventSuccess) { | ||||||
|             nfc_worker_stop(nfc->worker); |             nfc_worker_stop(nfc->worker); | ||||||
|             if(nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name)) { |             if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); | ||||||
|  | |||||||
| @ -48,7 +48,10 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e | |||||||
|            NFC_MF_UL_DATA_CHANGED) { |            NFC_MF_UL_DATA_CHANGED) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); |                 nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); | ||||||
|             nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); |             // Save shadow file
 | ||||||
|  |             if(furi_string_size(nfc->dev->load_path)) { | ||||||
|  |                 nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         consumed = false; |         consumed = false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -62,7 +62,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; |                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; | ||||||
|             } |             } | ||||||
|             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); |             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); | ||||||
|             if(nfc_device_save(nfc->dev, nfc->text_store)) { |             if(nfc_save_file(nfc)) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||||
|                 if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { |                 if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { | ||||||
|                     // Nothing, do not count editing as saving
 |                     // Nothing, do not count editing as saving
 | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { |             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { | ||||||
|                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; |                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; | ||||||
|                 if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { |                 if(nfc_save_file(nfc)) { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||||
|                     consumed = true; |                     consumed = true; | ||||||
|                 } |                 } | ||||||
| @ -41,6 +41,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -81,6 +81,7 @@ FIRMWARE_APPS = { | |||||||
|         "basic_services", |         "basic_services", | ||||||
|         "updater_app", |         "updater_app", | ||||||
|         "unit_tests", |         "unit_tests", | ||||||
|  |         "nfc", | ||||||
|     ], |     ], | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,7.3,, | Version,+,7.4,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -1844,6 +1844,7 @@ Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, | |||||||
| Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t | Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t | ||||||
| Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t | Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t | ||||||
| Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" | Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" | ||||||
|  | Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType | ||||||
| Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType | Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType | ||||||
| Function,-,mf_classic_get_type_str,const char*,MfClassicType | Function,-,mf_classic_get_type_str,const char*,MfClassicType | ||||||
| Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" | Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" | ||||||
|  | |||||||
| 
 | 
| @ -1006,12 +1006,7 @@ static void nfc_device_get_shadow_path(FuriString* orig_path, FuriString* shadow | |||||||
|     furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION); |     furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool nfc_device_save_file( | bool nfc_device_save(NfcDevice* dev, const char* dev_name) { | ||||||
|     NfcDevice* dev, |  | ||||||
|     const char* dev_name, |  | ||||||
|     const char* folder, |  | ||||||
|     const char* extension, |  | ||||||
|     bool use_load_path) { |  | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
|     bool saved = false; |     bool saved = false; | ||||||
| @ -1021,19 +1016,10 @@ static bool nfc_device_save_file( | |||||||
|     temp_str = furi_string_alloc(); |     temp_str = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(use_load_path && !furi_string_empty(dev->load_path)) { |  | ||||||
|             // Get directory name
 |  | ||||||
|             path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str); |  | ||||||
|             // Create nfc directory if necessary
 |  | ||||||
|             if(!storage_simply_mkdir(dev->storage, furi_string_get_cstr(temp_str))) break; |  | ||||||
|             // Make path to file to save
 |  | ||||||
|             furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension); |  | ||||||
|         } else { |  | ||||||
|         // Create nfc directory if necessary
 |         // Create nfc directory if necessary
 | ||||||
|         if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break; |         if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break; | ||||||
|         // First remove nfc device file if it was saved
 |         // First remove nfc device file if it was saved
 | ||||||
|             furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); |         furi_string_printf(temp_str, "%s", dev_name); | ||||||
|         } |  | ||||||
|         // Open file
 |         // Open file
 | ||||||
|         if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break; |         if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break; | ||||||
|         // Write header
 |         // Write header
 | ||||||
| @ -1072,13 +1058,19 @@ static bool nfc_device_save_file( | |||||||
|     return saved; |     return saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_device_save(NfcDevice* dev, const char* dev_name) { | bool nfc_device_save_shadow(NfcDevice* dev, const char* path) { | ||||||
|     return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { |  | ||||||
|     dev->shadow_file_exist = true; |     dev->shadow_file_exist = true; | ||||||
|     return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION, true); |     // Replace extension from .nfc to .shd if necessary
 | ||||||
|  |     FuriString* orig_path = furi_string_alloc(); | ||||||
|  |     furi_string_set_str(orig_path, path); | ||||||
|  |     FuriString* shadow_path = furi_string_alloc(); | ||||||
|  |     nfc_device_get_shadow_path(orig_path, shadow_path); | ||||||
|  | 
 | ||||||
|  |     bool file_saved = nfc_device_save(dev, furi_string_get_cstr(shadow_path)); | ||||||
|  |     furi_string_free(orig_path); | ||||||
|  |     furi_string_free(shadow_path); | ||||||
|  | 
 | ||||||
|  |     return file_saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) { | static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) { | ||||||
| @ -1195,7 +1187,7 @@ bool nfc_file_select(NfcDevice* dev) { | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     bool res = |     bool res = | ||||||
|         dialog_file_browser_show(dev->dialogs, dev->load_path, nfc_app_folder, &browser_options); |         dialog_file_browser_show(dev->dialogs, dev->load_path, dev->load_path, &browser_options); | ||||||
| 
 | 
 | ||||||
|     furi_string_free(nfc_app_folder); |     furi_string_free(nfc_app_folder); | ||||||
|     if(res) { |     if(res) { | ||||||
|  | |||||||
| @ -82,7 +82,7 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static uint16_t mf_classic_get_total_block_num(MfClassicType type) { | uint16_t mf_classic_get_total_block_num(MfClassicType type) { | ||||||
|     if(type == MfClassicType1k) { |     if(type == MfClassicType1k) { | ||||||
|         return 64; |         return 64; | ||||||
|     } else if(type == MfClassicType4k) { |     } else if(type == MfClassicType4k) { | ||||||
|  | |||||||
| @ -98,6 +98,8 @@ MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t S | |||||||
| 
 | 
 | ||||||
| uint8_t mf_classic_get_total_sectors_num(MfClassicType type); | uint8_t mf_classic_get_total_sectors_num(MfClassicType type); | ||||||
| 
 | 
 | ||||||
|  | uint16_t mf_classic_get_total_block_num(MfClassicType type); | ||||||
|  | 
 | ||||||
| uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); | uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); | ||||||
| 
 | 
 | ||||||
| bool mf_classic_is_sector_trailer(uint8_t block); | bool mf_classic_is_sector_trailer(uint8_t block); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Astra
						Astra