diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index f149508b..8009f6a1 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -16,6 +16,7 @@ #define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/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_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") static const char* nfc_test_file_type = "Flipper NFC test"; static const uint32_t nfc_test_file_version = 1; @@ -220,11 +221,78 @@ MU_TEST(mf_classic_dict_test) { furi_string_free(temp_str); } +MU_TEST(mf_classic_dict_load_test) { + Storage* storage = furi_record_open(RECORD_STORAGE); + mu_assert(storage != NULL, "storage != NULL assert failed\r\n"); + + // Delete unit test dict file if exists + if(storage_file_exists(storage, NFC_TEST_DICT_PATH)) { + mu_assert( + storage_simply_remove(storage, NFC_TEST_DICT_PATH), + "remove == true assert failed\r\n"); + } + + // Create unit test dict file + Stream* file_stream = file_stream_alloc(storage); + mu_assert(file_stream != NULL, "file_stream != NULL assert failed\r\n"); + mu_assert( + file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS), + "file_stream_open == true assert failed\r\n"); + + // Write unit test dict file + char key_str[] = "a0a1a2a3a4a5"; + mu_assert( + stream_write_cstring(file_stream, key_str) == strlen(key_str), + "write == true assert failed\r\n"); + // Close unit test dict file + mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); + + // Load unit test dict file + MfClassicDict* instance = NULL; + instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); + mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); + uint32_t total_keys = mf_classic_dict_get_total_keys(instance); + mu_assert(total_keys == 1, "total_keys == 1 assert failed\r\n"); + + // Read key + uint64_t key_ref = 0xa0a1a2a3a4a5; + uint64_t key_dut = 0; + FuriString* temp_str = furi_string_alloc(); + mu_assert( + mf_classic_dict_get_next_key_str(instance, temp_str), + "get_next_key_str == true assert failed\r\n"); + mu_assert(furi_string_cmp_str(temp_str, key_str) == 0, "invalid key loaded\r\n"); + mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + mu_assert( + mf_classic_dict_get_next_key(instance, &key_dut), + "get_next_key == true assert failed\r\n"); + mu_assert(key_dut == key_ref, "invalid key loaded\r\n"); + furi_string_free(temp_str); + mf_classic_dict_free(instance); + + // Check that MfClassicDict added new line to the end of the file + mu_assert( + file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING), + "file_stream_open == true assert failed\r\n"); + mu_assert(stream_seek(file_stream, -1, StreamOffsetFromEnd), "seek == true assert failed\r\n"); + uint8_t last_char = 0; + mu_assert(stream_read(file_stream, &last_char, 1) == 1, "read == true assert failed\r\n"); + mu_assert(last_char == '\n', "last_char == '\\n' assert failed\r\n"); + mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); + + // Delete unit test dict file + mu_assert( + storage_simply_remove(storage, NFC_TEST_DICT_PATH), "remove == true assert failed\r\n"); + stream_free(file_stream); + furi_record_close(RECORD_STORAGE); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); MU_RUN_TEST(nfc_digital_signal_test); MU_RUN_TEST(mf_classic_dict_test); + MU_RUN_TEST(mf_classic_dict_load_test); nfc_test_free(); } diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c index a842ed92..690bba61 100644 --- a/lib/nfc/helpers/mf_classic_dict.c +++ b/lib/nfc/helpers/mf_classic_dict.c @@ -44,7 +44,10 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { do { if(dict_type == MfClassicDictTypeFlipper) { if(!buffered_file_stream_open( - dict->stream, MF_CLASSIC_DICT_FLIPPER_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + dict->stream, + MF_CLASSIC_DICT_FLIPPER_PATH, + FSAM_READ_WRITE, + FSOM_OPEN_EXISTING)) { buffered_file_stream_close(dict->stream); break; } @@ -59,12 +62,24 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { dict->stream, MF_CLASSIC_DICT_UNIT_TEST_PATH, FSAM_READ_WRITE, - FSOM_CREATE_ALWAYS)) { + FSOM_OPEN_ALWAYS)) { buffered_file_stream_close(dict->stream); break; } } + // Check for new line ending + if(!stream_eof(dict->stream)) { + if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break; + uint8_t last_char = 0; + if(stream_read(dict->stream, &last_char, 1) != 1) break; + if(last_char != '\n') { + FURI_LOG_D(TAG, "Adding new line ending"); + if(stream_write_char(dict->stream, '\n') != 1) break; + } + if(!stream_rewind(dict->stream)) break; + } + // Read total amount of keys FuriString* next_line; next_line = furi_string_alloc(); @@ -73,14 +88,13 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { FURI_LOG_T(TAG, "No keys left in dict"); break; } - furi_string_trim(next_line); FURI_LOG_T( TAG, "Read line: %s, len: %d", furi_string_get_cstr(next_line), furi_string_size(next_line)); if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN - 1) continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; dict->total_keys++; } furi_string_free(next_line); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 06d57a0c..740cfae5 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -921,7 +921,7 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { file, furi_string_get_cstr(temp_str), sec_tr->key_a, 6); } if(!key_save_success) break; - if(FURI_BIT(data->key_a_mask, i)) { + if(FURI_BIT(data->key_b_mask, i)) { furi_string_printf(temp_str, "Key B sector %d", i); key_save_success = flipper_format_write_hex( file, furi_string_get_cstr(temp_str), sec_tr->key_b, 6);