[FL-3008], [FL-2734], [FL-2766], [FL-2898] NFC bug fixes (#2098)
* nfc: rework mf classic update * nfc: rename cache folder to .cache * nfc: fix ATQA order bytes in nfc files * file browser: add hide dot files option * nfc: fix iso-14443-4 uid cards emulation * nfc: fix unit tests Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									c43ec414bb
								
							
						
					
					
						commit
						9a21dae29c
					
				@ -393,7 +393,7 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
 | 
				
			|||||||
        "nfc_device_save == true assert failed\r\n");
 | 
					        "nfc_device_save == true assert failed\r\n");
 | 
				
			||||||
    // Verify that key cache is saved
 | 
					    // Verify that key cache is saved
 | 
				
			||||||
    FuriString* key_cache_name = furi_string_alloc();
 | 
					    FuriString* key_cache_name = furi_string_alloc();
 | 
				
			||||||
    furi_string_set_str(key_cache_name, "/ext/nfc/cache/");
 | 
					    furi_string_set_str(key_cache_name, "/ext/nfc/.cache/");
 | 
				
			||||||
    for(size_t i = 0; i < uid_len; i++) {
 | 
					    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, "%02X", uid[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -80,10 +80,11 @@ static void archive_file_browser_set_path(
 | 
				
			|||||||
    ArchiveBrowserView* browser,
 | 
					    ArchiveBrowserView* browser,
 | 
				
			||||||
    FuriString* path,
 | 
					    FuriString* path,
 | 
				
			||||||
    const char* filter_ext,
 | 
					    const char* filter_ext,
 | 
				
			||||||
    bool skip_assets) {
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files) {
 | 
				
			||||||
    furi_assert(browser);
 | 
					    furi_assert(browser);
 | 
				
			||||||
    if(!browser->worker_running) {
 | 
					    if(!browser->worker_running) {
 | 
				
			||||||
        browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets);
 | 
					        browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets, hide_dot_files);
 | 
				
			||||||
        file_browser_worker_set_callback_context(browser->worker, browser);
 | 
					        file_browser_worker_set_callback_context(browser->worker, browser);
 | 
				
			||||||
        file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
 | 
					        file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
 | 
				
			||||||
        file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
 | 
					        file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
 | 
				
			||||||
@ -92,7 +93,8 @@ static void archive_file_browser_set_path(
 | 
				
			|||||||
        browser->worker_running = true;
 | 
					        browser->worker_running = true;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        furi_assert(browser->worker);
 | 
					        furi_assert(browser->worker);
 | 
				
			||||||
        file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets);
 | 
					        file_browser_worker_set_config(
 | 
				
			||||||
 | 
					            browser->worker, path, filter_ext, skip_assets, hide_dot_files);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -473,7 +475,7 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
 | 
				
			|||||||
        if(archive_is_dir_exists(browser->path)) {
 | 
					        if(archive_is_dir_exists(browser->path)) {
 | 
				
			||||||
            bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
 | 
					            bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
 | 
				
			||||||
            archive_file_browser_set_path(
 | 
					            archive_file_browser_set_path(
 | 
				
			||||||
                browser, browser->path, archive_get_tab_ext(tab), skip_assets);
 | 
					                browser, browser->path, archive_get_tab_ext(tab), skip_assets, false);
 | 
				
			||||||
            tab_empty = false; // Empty check will be performed later
 | 
					            tab_empty = false; // Empty check will be performed later
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ typedef struct DialogsApp DialogsApp;
 | 
				
			|||||||
 * File browser dialog extra options
 | 
					 * File browser dialog extra options
 | 
				
			||||||
 * @param extension file extension to be offered for selection
 | 
					 * @param extension file extension to be offered for selection
 | 
				
			||||||
 * @param skip_assets true - do not show assets folders
 | 
					 * @param skip_assets true - do not show assets folders
 | 
				
			||||||
 | 
					 * @param hide_dot_files true - hide dot files
 | 
				
			||||||
 * @param icon file icon pointer, NULL for default icon
 | 
					 * @param icon file icon pointer, NULL for default icon
 | 
				
			||||||
 * @param hide_ext true - hide extensions for files
 | 
					 * @param hide_ext true - hide extensions for files
 | 
				
			||||||
 * @param item_loader_callback callback function for providing custom icon & entry name
 | 
					 * @param item_loader_callback callback function for providing custom icon & entry name
 | 
				
			||||||
@ -27,6 +28,7 @@ typedef struct DialogsApp DialogsApp;
 | 
				
			|||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    const char* extension;
 | 
					    const char* extension;
 | 
				
			||||||
    bool skip_assets;
 | 
					    bool skip_assets;
 | 
				
			||||||
 | 
					    bool hide_dot_files;
 | 
				
			||||||
    const Icon* icon;
 | 
					    const Icon* icon;
 | 
				
			||||||
    bool hide_ext;
 | 
					    bool hide_ext;
 | 
				
			||||||
    FileBrowserLoadItemCallback item_loader_callback;
 | 
					    FileBrowserLoadItemCallback item_loader_callback;
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,7 @@ bool dialog_file_browser_show(
 | 
				
			|||||||
            .file_icon = options ? options->icon : NULL,
 | 
					            .file_icon = options ? options->icon : NULL,
 | 
				
			||||||
            .hide_ext = options ? options->hide_ext : true,
 | 
					            .hide_ext = options ? options->hide_ext : true,
 | 
				
			||||||
            .skip_assets = options ? options->skip_assets : true,
 | 
					            .skip_assets = options ? options->skip_assets : true,
 | 
				
			||||||
 | 
					            .hide_dot_files = options ? options->hide_dot_files : true,
 | 
				
			||||||
            .preselected_filename = path,
 | 
					            .preselected_filename = path,
 | 
				
			||||||
            .item_callback = options ? options->item_loader_callback : NULL,
 | 
					            .item_callback = options ? options->item_loader_callback : NULL,
 | 
				
			||||||
            .item_callback_context = options ? options->item_loader_context : NULL,
 | 
					            .item_callback_context = options ? options->item_loader_context : NULL,
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ typedef struct {
 | 
				
			|||||||
    const char* extension;
 | 
					    const char* extension;
 | 
				
			||||||
    bool skip_assets;
 | 
					    bool skip_assets;
 | 
				
			||||||
    bool hide_ext;
 | 
					    bool hide_ext;
 | 
				
			||||||
 | 
					    bool hide_dot_files;
 | 
				
			||||||
    const Icon* file_icon;
 | 
					    const Icon* file_icon;
 | 
				
			||||||
    FuriString* result_path;
 | 
					    FuriString* result_path;
 | 
				
			||||||
    FuriString* preselected_filename;
 | 
					    FuriString* preselected_filename;
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,12 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
 | 
				
			|||||||
    file_browser_set_callback(
 | 
					    file_browser_set_callback(
 | 
				
			||||||
        file_browser, dialogs_app_file_browser_callback, file_browser_context);
 | 
					        file_browser, dialogs_app_file_browser_callback, file_browser_context);
 | 
				
			||||||
    file_browser_configure(
 | 
					    file_browser_configure(
 | 
				
			||||||
        file_browser, data->extension, data->skip_assets, data->file_icon, data->hide_ext);
 | 
					        file_browser,
 | 
				
			||||||
 | 
					        data->extension,
 | 
				
			||||||
 | 
					        data->skip_assets,
 | 
				
			||||||
 | 
					        data->hide_dot_files,
 | 
				
			||||||
 | 
					        data->file_icon,
 | 
				
			||||||
 | 
					        data->hide_ext);
 | 
				
			||||||
    file_browser_set_item_callback(file_browser, data->item_callback, data->item_callback_context);
 | 
					    file_browser_set_item_callback(file_browser, data->item_callback, data->item_callback_context);
 | 
				
			||||||
    file_browser_start(file_browser, data->preselected_filename);
 | 
					    file_browser_start(file_browser, data->preselected_filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -84,6 +84,7 @@ struct FileBrowser {
 | 
				
			|||||||
    BrowserWorker* worker;
 | 
					    BrowserWorker* worker;
 | 
				
			||||||
    const char* ext_filter;
 | 
					    const char* ext_filter;
 | 
				
			||||||
    bool skip_assets;
 | 
					    bool skip_assets;
 | 
				
			||||||
 | 
					    bool hide_dot_files;
 | 
				
			||||||
    bool hide_ext;
 | 
					    bool hide_ext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FileBrowserCallback callback;
 | 
					    FileBrowserCallback callback;
 | 
				
			||||||
@ -163,6 +164,7 @@ void file_browser_configure(
 | 
				
			|||||||
    FileBrowser* browser,
 | 
					    FileBrowser* browser,
 | 
				
			||||||
    const char* extension,
 | 
					    const char* extension,
 | 
				
			||||||
    bool skip_assets,
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files,
 | 
				
			||||||
    const Icon* file_icon,
 | 
					    const Icon* file_icon,
 | 
				
			||||||
    bool hide_ext) {
 | 
					    bool hide_ext) {
 | 
				
			||||||
    furi_assert(browser);
 | 
					    furi_assert(browser);
 | 
				
			||||||
@ -170,6 +172,7 @@ void file_browser_configure(
 | 
				
			|||||||
    browser->ext_filter = extension;
 | 
					    browser->ext_filter = extension;
 | 
				
			||||||
    browser->skip_assets = skip_assets;
 | 
					    browser->skip_assets = skip_assets;
 | 
				
			||||||
    browser->hide_ext = hide_ext;
 | 
					    browser->hide_ext = hide_ext;
 | 
				
			||||||
 | 
					    browser->hide_dot_files = hide_dot_files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with_view_model(
 | 
					    with_view_model(
 | 
				
			||||||
        browser->view,
 | 
					        browser->view,
 | 
				
			||||||
@ -183,7 +186,8 @@ void file_browser_configure(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void file_browser_start(FileBrowser* browser, FuriString* path) {
 | 
					void file_browser_start(FileBrowser* browser, FuriString* path) {
 | 
				
			||||||
    furi_assert(browser);
 | 
					    furi_assert(browser);
 | 
				
			||||||
    browser->worker = file_browser_worker_alloc(path, browser->ext_filter, browser->skip_assets);
 | 
					    browser->worker = file_browser_worker_alloc(
 | 
				
			||||||
 | 
					        path, browser->ext_filter, browser->skip_assets, browser->hide_dot_files);
 | 
				
			||||||
    file_browser_worker_set_callback_context(browser->worker, browser);
 | 
					    file_browser_worker_set_callback_context(browser->worker, browser);
 | 
				
			||||||
    file_browser_worker_set_folder_callback(browser->worker, browser_folder_open_cb);
 | 
					    file_browser_worker_set_folder_callback(browser->worker, browser_folder_open_cb);
 | 
				
			||||||
    file_browser_worker_set_list_callback(browser->worker, browser_list_load_cb);
 | 
					    file_browser_worker_set_list_callback(browser->worker, browser_list_load_cb);
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ void file_browser_configure(
 | 
				
			|||||||
    FileBrowser* browser,
 | 
					    FileBrowser* browser,
 | 
				
			||||||
    const char* extension,
 | 
					    const char* extension,
 | 
				
			||||||
    bool skip_assets,
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files,
 | 
				
			||||||
    const Icon* file_icon,
 | 
					    const Icon* file_icon,
 | 
				
			||||||
    bool hide_ext);
 | 
					    bool hide_ext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,7 @@ struct BrowserWorker {
 | 
				
			|||||||
    uint32_t load_offset;
 | 
					    uint32_t load_offset;
 | 
				
			||||||
    uint32_t load_count;
 | 
					    uint32_t load_count;
 | 
				
			||||||
    bool skip_assets;
 | 
					    bool skip_assets;
 | 
				
			||||||
 | 
					    bool hide_dot_files;
 | 
				
			||||||
    idx_last_array_t idx_last;
 | 
					    idx_last_array_t idx_last;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void* cb_ctx;
 | 
					    void* cb_ctx;
 | 
				
			||||||
@ -76,6 +77,13 @@ static bool browser_path_trim(FuriString* path) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, bool is_folder) {
 | 
					static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, bool is_folder) {
 | 
				
			||||||
 | 
					    // Skip dot files if enabled
 | 
				
			||||||
 | 
					    if(browser->hide_dot_files) {
 | 
				
			||||||
 | 
					        if(furi_string_start_with_str(name, ".")) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(is_folder) {
 | 
					    if(is_folder) {
 | 
				
			||||||
        // Skip assets folders (if enabled)
 | 
					        // Skip assets folders (if enabled)
 | 
				
			||||||
        if(browser->skip_assets) {
 | 
					        if(browser->skip_assets) {
 | 
				
			||||||
@ -361,14 +369,18 @@ static int32_t browser_worker(void* context) {
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BrowserWorker*
 | 
					BrowserWorker* file_browser_worker_alloc(
 | 
				
			||||||
    file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets) {
 | 
					    FuriString* path,
 | 
				
			||||||
 | 
					    const char* filter_ext,
 | 
				
			||||||
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files) {
 | 
				
			||||||
    BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
 | 
					    BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    idx_last_array_init(browser->idx_last);
 | 
					    idx_last_array_init(browser->idx_last);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    browser->filter_extension = furi_string_alloc_set(filter_ext);
 | 
					    browser->filter_extension = furi_string_alloc_set(filter_ext);
 | 
				
			||||||
    browser->skip_assets = skip_assets;
 | 
					    browser->skip_assets = skip_assets;
 | 
				
			||||||
 | 
					    browser->hide_dot_files = hide_dot_files;
 | 
				
			||||||
    browser->path_start = furi_string_alloc_set(path);
 | 
					    browser->path_start = furi_string_alloc_set(path);
 | 
				
			||||||
    browser->path_current = furi_string_alloc_set(path);
 | 
					    browser->path_current = furi_string_alloc_set(path);
 | 
				
			||||||
    browser->path_next = furi_string_alloc_set(path);
 | 
					    browser->path_next = furi_string_alloc_set(path);
 | 
				
			||||||
@ -437,11 +449,13 @@ void file_browser_worker_set_config(
 | 
				
			|||||||
    BrowserWorker* browser,
 | 
					    BrowserWorker* browser,
 | 
				
			||||||
    FuriString* path,
 | 
					    FuriString* path,
 | 
				
			||||||
    const char* filter_ext,
 | 
					    const char* filter_ext,
 | 
				
			||||||
    bool skip_assets) {
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files) {
 | 
				
			||||||
    furi_assert(browser);
 | 
					    furi_assert(browser);
 | 
				
			||||||
    furi_string_set(browser->path_next, path);
 | 
					    furi_string_set(browser->path_next, path);
 | 
				
			||||||
    furi_string_set(browser->filter_extension, filter_ext);
 | 
					    furi_string_set(browser->filter_extension, filter_ext);
 | 
				
			||||||
    browser->skip_assets = skip_assets;
 | 
					    browser->skip_assets = skip_assets;
 | 
				
			||||||
 | 
					    browser->hide_dot_files = hide_dot_files;
 | 
				
			||||||
    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
 | 
					    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -21,8 +21,11 @@ typedef void (*BrowserWorkerListItemCallback)(
 | 
				
			|||||||
    bool is_last);
 | 
					    bool is_last);
 | 
				
			||||||
typedef void (*BrowserWorkerLongLoadCallback)(void* context);
 | 
					typedef void (*BrowserWorkerLongLoadCallback)(void* context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BrowserWorker*
 | 
					BrowserWorker* file_browser_worker_alloc(
 | 
				
			||||||
    file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets);
 | 
					    FuriString* path,
 | 
				
			||||||
 | 
					    const char* filter_ext,
 | 
				
			||||||
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void file_browser_worker_free(BrowserWorker* browser);
 | 
					void file_browser_worker_free(BrowserWorker* browser);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,7 +51,8 @@ void file_browser_worker_set_config(
 | 
				
			|||||||
    BrowserWorker* browser,
 | 
					    BrowserWorker* browser,
 | 
				
			||||||
    FuriString* path,
 | 
					    FuriString* path,
 | 
				
			||||||
    const char* filter_ext,
 | 
					    const char* filter_ext,
 | 
				
			||||||
    bool skip_assets);
 | 
					    bool skip_assets,
 | 
				
			||||||
 | 
					    bool hide_dot_files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, int32_t item_idx);
 | 
					void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, int32_t item_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
entry,status,name,type,params
 | 
					entry,status,name,type,params
 | 
				
			||||||
Version,+,8.1,,
 | 
					Version,+,9.0,,
 | 
				
			||||||
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,,
 | 
				
			||||||
@ -806,14 +806,14 @@ Function,-,fgetpos,int,"FILE*, fpos_t*"
 | 
				
			|||||||
Function,-,fgets,char*,"char*, int, FILE*"
 | 
					Function,-,fgets,char*,"char*, int, FILE*"
 | 
				
			||||||
Function,-,fgets_unlocked,char*,"char*, int, FILE*"
 | 
					Function,-,fgets_unlocked,char*,"char*, int, FILE*"
 | 
				
			||||||
Function,+,file_browser_alloc,FileBrowser*,FuriString*
 | 
					Function,+,file_browser_alloc,FileBrowser*,FuriString*
 | 
				
			||||||
Function,+,file_browser_configure,void,"FileBrowser*, const char*, _Bool, const Icon*, _Bool"
 | 
					Function,+,file_browser_configure,void,"FileBrowser*, const char*, _Bool, _Bool, const Icon*, _Bool"
 | 
				
			||||||
Function,+,file_browser_free,void,FileBrowser*
 | 
					Function,+,file_browser_free,void,FileBrowser*
 | 
				
			||||||
Function,+,file_browser_get_view,View*,FileBrowser*
 | 
					Function,+,file_browser_get_view,View*,FileBrowser*
 | 
				
			||||||
Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*"
 | 
					Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*"
 | 
				
			||||||
Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*"
 | 
					Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*"
 | 
				
			||||||
Function,+,file_browser_start,void,"FileBrowser*, FuriString*"
 | 
					Function,+,file_browser_start,void,"FileBrowser*, FuriString*"
 | 
				
			||||||
Function,+,file_browser_stop,void,FileBrowser*
 | 
					Function,+,file_browser_stop,void,FileBrowser*
 | 
				
			||||||
Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, _Bool"
 | 
					Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, _Bool, _Bool"
 | 
				
			||||||
Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t"
 | 
					Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t"
 | 
				
			||||||
Function,+,file_browser_worker_folder_exit,void,BrowserWorker*
 | 
					Function,+,file_browser_worker_folder_exit,void,BrowserWorker*
 | 
				
			||||||
Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t"
 | 
					Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t"
 | 
				
			||||||
@ -821,7 +821,7 @@ Function,+,file_browser_worker_free,void,BrowserWorker*
 | 
				
			|||||||
Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker*
 | 
					Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker*
 | 
				
			||||||
Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t"
 | 
					Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t"
 | 
				
			||||||
Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*"
 | 
					Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*"
 | 
				
			||||||
Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool"
 | 
					Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool, _Bool"
 | 
				
			||||||
Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback"
 | 
					Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback"
 | 
				
			||||||
Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback"
 | 
					Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback"
 | 
				
			||||||
Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback"
 | 
					Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback"
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
@ -244,6 +244,9 @@ bool furi_hal_nfc_listen(
 | 
				
			|||||||
    params.lmConfigPA.SEL_RES = sak;
 | 
					    params.lmConfigPA.SEL_RES = sak;
 | 
				
			||||||
    rfalNfcDiscover(¶ms);
 | 
					    rfalNfcDiscover(¶ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Disable EMD suppression.
 | 
				
			||||||
 | 
					    st25r3916ModifyRegister(ST25R3916_REG_EMD_SUP_CONF, ST25R3916_REG_EMD_SUP_CONF_emd_emv, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t start = DWT->CYCCNT;
 | 
					    uint32_t start = DWT->CYCCNT;
 | 
				
			||||||
    while(state != RFAL_NFC_STATE_ACTIVATED) {
 | 
					    while(state != RFAL_NFC_STATE_ACTIVATED) {
 | 
				
			||||||
        rfalNfcWorker();
 | 
					        rfalNfcWorker();
 | 
				
			||||||
 | 
				
			|||||||
@ -8,11 +8,11 @@
 | 
				
			|||||||
#include <flipper_format/flipper_format.h>
 | 
					#include <flipper_format/flipper_format.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TAG "NfcDevice"
 | 
					#define TAG "NfcDevice"
 | 
				
			||||||
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache")
 | 
					#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/.cache")
 | 
				
			||||||
#define NFC_DEVICE_KEYS_EXTENSION ".keys"
 | 
					#define NFC_DEVICE_KEYS_EXTENSION ".keys"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char* nfc_file_header = "Flipper NFC device";
 | 
					static const char* nfc_file_header = "Flipper NFC device";
 | 
				
			||||||
static const uint32_t nfc_file_version = 2;
 | 
					static const uint32_t nfc_file_version = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char* nfc_keys_file_header = "Flipper NFC keys";
 | 
					static const char* nfc_keys_file_header = "Flipper NFC keys";
 | 
				
			||||||
static const uint32_t nfc_keys_file_version = 1;
 | 
					static const uint32_t nfc_keys_file_version = 1;
 | 
				
			||||||
@ -27,6 +27,11 @@ NfcDevice* nfc_device_alloc() {
 | 
				
			|||||||
    nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
 | 
					    nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
 | 
				
			||||||
    nfc_dev->load_path = furi_string_alloc();
 | 
					    nfc_dev->load_path = furi_string_alloc();
 | 
				
			||||||
    nfc_dev->dev_data.parsed_data = furi_string_alloc();
 | 
					    nfc_dev->dev_data.parsed_data = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Rename cache folder name for backward compatibility
 | 
				
			||||||
 | 
					    if(storage_common_stat(nfc_dev->storage, "/ext/nfc/cache", NULL) == FSE_OK) {
 | 
				
			||||||
 | 
					        storage_common_rename(nfc_dev->storage, "/ext/nfc/cache", NFC_DEVICE_KEYS_FOLDER);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return nfc_dev;
 | 
					    return nfc_dev;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1041,7 +1046,9 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
 | 
				
			|||||||
        if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
 | 
					        if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
 | 
					        if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
 | 
				
			||||||
        if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break;
 | 
					        // Save ATQA in MSB order for correct companion apps display
 | 
				
			||||||
 | 
					        uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
 | 
				
			||||||
 | 
					        if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
 | 
				
			||||||
        if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
 | 
					        if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
 | 
				
			||||||
        // Save more data if necessary
 | 
					        // Save more data if necessary
 | 
				
			||||||
        if(dev->format == NfcDeviceSaveFormatMifareUl) {
 | 
					        if(dev->format == NfcDeviceSaveFormatMifareUl) {
 | 
				
			||||||
@ -1089,6 +1096,9 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
 | 
				
			|||||||
    temp_str = furi_string_alloc();
 | 
					    temp_str = furi_string_alloc();
 | 
				
			||||||
    bool deprecated_version = false;
 | 
					    bool deprecated_version = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Version 2 of file format had ATQA bytes swapped
 | 
				
			||||||
 | 
					    uint32_t version_with_lsb_atqa = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(dev->loading_cb) {
 | 
					    if(dev->loading_cb) {
 | 
				
			||||||
        dev->loading_cb(dev->loading_cb_ctx, true);
 | 
					        dev->loading_cb(dev->loading_cb_ctx, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1107,9 +1117,12 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
 | 
				
			|||||||
        // Read and verify file header
 | 
					        // Read and verify file header
 | 
				
			||||||
        uint32_t version = 0;
 | 
					        uint32_t version = 0;
 | 
				
			||||||
        if(!flipper_format_read_header(file, temp_str, &version)) break;
 | 
					        if(!flipper_format_read_header(file, temp_str, &version)) break;
 | 
				
			||||||
        if(furi_string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
 | 
					        if(furi_string_cmp_str(temp_str, nfc_file_header)) break;
 | 
				
			||||||
            deprecated_version = true;
 | 
					        if(version != nfc_file_version) {
 | 
				
			||||||
            break;
 | 
					            if(version < version_with_lsb_atqa) {
 | 
				
			||||||
 | 
					                deprecated_version = true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // Read Nfc device type
 | 
					        // Read Nfc device type
 | 
				
			||||||
        if(!flipper_format_read_string(file, "Device type", temp_str)) break;
 | 
					        if(!flipper_format_read_string(file, "Device type", temp_str)) break;
 | 
				
			||||||
@ -1119,7 +1132,14 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
 | 
				
			|||||||
        if(!(data_cnt == 4 || data_cnt == 7)) break;
 | 
					        if(!(data_cnt == 4 || data_cnt == 7)) break;
 | 
				
			||||||
        data->uid_len = data_cnt;
 | 
					        data->uid_len = data_cnt;
 | 
				
			||||||
        if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
 | 
					        if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
 | 
				
			||||||
        if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
 | 
					        if(version == version_with_lsb_atqa) {
 | 
				
			||||||
 | 
					            if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            uint8_t atqa[2] = {};
 | 
				
			||||||
 | 
					            if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break;
 | 
				
			||||||
 | 
					            data->atqa[0] = atqa[1];
 | 
				
			||||||
 | 
					            data->atqa[1] = atqa[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
 | 
					        if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
 | 
				
			||||||
        // Load CUID
 | 
					        // Load CUID
 | 
				
			||||||
        uint8_t* cuid_start = data->uid;
 | 
					        uint8_t* cuid_start = data->uid;
 | 
				
			||||||
@ -1187,6 +1207,7 @@ bool nfc_file_select(NfcDevice* dev) {
 | 
				
			|||||||
    const DialogsFileBrowserOptions browser_options = {
 | 
					    const DialogsFileBrowserOptions browser_options = {
 | 
				
			||||||
        .extension = NFC_APP_EXTENSION,
 | 
					        .extension = NFC_APP_EXTENSION,
 | 
				
			||||||
        .skip_assets = true,
 | 
					        .skip_assets = true,
 | 
				
			||||||
 | 
					        .hide_dot_files = true,
 | 
				
			||||||
        .icon = &I_Nfc_10px,
 | 
					        .icon = &I_Nfc_10px,
 | 
				
			||||||
        .hide_ext = true,
 | 
					        .hide_ext = true,
 | 
				
			||||||
        .item_loader_callback = NULL,
 | 
					        .item_loader_callback = NULL,
 | 
				
			||||||
 | 
				
			|||||||
@ -712,46 +712,16 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data
 | 
				
			|||||||
    furi_assert(tx_rx);
 | 
					    furi_assert(tx_rx);
 | 
				
			||||||
    furi_assert(data);
 | 
					    furi_assert(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t sectors_read = 0;
 | 
					 | 
				
			||||||
    Crypto1 crypto = {};
 | 
					 | 
				
			||||||
    uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type);
 | 
					    uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type);
 | 
				
			||||||
    uint64_t key_a = 0;
 | 
					 | 
				
			||||||
    uint64_t key_b = 0;
 | 
					 | 
				
			||||||
    MfClassicSectorReader sec_reader = {};
 | 
					 | 
				
			||||||
    MfClassicSector temp_sector = {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(size_t i = 0; i < total_sectors; i++) {
 | 
					    for(size_t i = 0; i < total_sectors; i++) {
 | 
				
			||||||
        MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
 | 
					        mf_classic_read_sector(tx_rx, data, i);
 | 
				
			||||||
        // Load key A
 | 
					 | 
				
			||||||
        if(mf_classic_is_key_found(data, i, MfClassicKeyA)) {
 | 
					 | 
				
			||||||
            sec_reader.key_a = nfc_util_bytes2num(sec_tr->key_a, 6);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            sec_reader.key_a = MF_CLASSIC_NO_KEY;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Load key B
 | 
					 | 
				
			||||||
        if(mf_classic_is_key_found(data, i, MfClassicKeyB)) {
 | 
					 | 
				
			||||||
            sec_reader.key_b = nfc_util_bytes2num(sec_tr->key_b, 6);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            sec_reader.key_b = MF_CLASSIC_NO_KEY;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY)) {
 | 
					 | 
				
			||||||
            sec_reader.sector_num = i;
 | 
					 | 
				
			||||||
            if(mf_classic_read_sector_with_reader(tx_rx, &crypto, &sec_reader, &temp_sector)) {
 | 
					 | 
				
			||||||
                uint8_t first_block = mf_classic_get_first_block_num_of_sector(i);
 | 
					 | 
				
			||||||
                for(uint8_t j = 0; j < temp_sector.total_blocks; j++) {
 | 
					 | 
				
			||||||
                    mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sectors_read++;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                // Invalid key, set it to not found
 | 
					 | 
				
			||||||
                if(key_a != MF_CLASSIC_NO_KEY) {
 | 
					 | 
				
			||||||
                    mf_classic_set_key_not_found(data, i, MfClassicKeyA);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    mf_classic_set_key_not_found(data, i, MfClassicKeyB);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    uint8_t sectors_read = 0;
 | 
				
			||||||
 | 
					    uint8_t keys_found = 0;
 | 
				
			||||||
 | 
					    mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found);
 | 
				
			||||||
 | 
					    FURI_LOG_D(TAG, "Read %d sectors and %d keys", sectors_read, keys_found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return sectors_read;
 | 
					    return sectors_read;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user