From b11161abb0626eb6ca55b0c0884ae08f5632d193 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Thu, 23 Mar 2023 22:53:10 +0300 Subject: [PATCH 01/16] Fix crash when emulating a DSGeneric key --- lib/ibutton/protocols/dallas/protocol_ds_generic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/ibutton/protocols/dallas/protocol_ds_generic.c index af355f461..6c698bb89 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds_generic.c +++ b/lib/ibutton/protocols/dallas/protocol_ds_generic.c @@ -62,6 +62,7 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat } static bool ds_generic_reset_callback(bool is_short, void* context) { + furi_assert(context); DallasGenericProtocolData* data = context; if(!is_short) { onewire_slave_set_overdrive(data->state.bus, is_short); @@ -93,7 +94,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { DallasGenericProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, NULL); + onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, protocol_data); onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data); } From fad24efdf076725468e8793d6d3d592e768dcd2a Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 24 Mar 2023 03:26:43 +0300 Subject: [PATCH 02/16] [FL-3188] Fix crash when emulating a DSGeneric key (#2530) --- lib/ibutton/protocols/dallas/protocol_ds_generic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/ibutton/protocols/dallas/protocol_ds_generic.c index af355f461..6c698bb89 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds_generic.c +++ b/lib/ibutton/protocols/dallas/protocol_ds_generic.c @@ -62,6 +62,7 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat } static bool ds_generic_reset_callback(bool is_short, void* context) { + furi_assert(context); DallasGenericProtocolData* data = context; if(!is_short) { onewire_slave_set_overdrive(data->state.bus, is_short); @@ -93,7 +94,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { DallasGenericProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, NULL); + onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, protocol_data); onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data); } From 5391b694d134a4a4efcf8d45dafd241b8ff08bbd Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Fri, 24 Mar 2023 21:06:36 +0300 Subject: [PATCH 03/16] Additional checks before invalidating the key --- lib/nfc/nfc_worker.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 4561ff2af..c2b89c71a 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -638,7 +638,8 @@ static void nfc_worker_mf_classic_key_attack( (uint32_t)key); if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); - FURI_LOG_D(TAG, "Key found"); + FURI_LOG_D( + TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); uint64_t found_key; @@ -661,7 +662,8 @@ static void nfc_worker_mf_classic_key_attack( (uint32_t)key); if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { mf_classic_set_key_found(data, i, MfClassicKeyB, key); - FURI_LOG_D(TAG, "Key found"); + FURI_LOG_D( + TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); } } @@ -760,9 +762,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { furi_hal_nfc_sleep(); deactivated = true; } else { - mf_classic_set_key_not_found(data, i, MfClassicKeyA); - is_key_a_found = false; - FURI_LOG_D(TAG, "Key %dA not found in attack", i); + // If the key A is marked as found and matches the searching key, invalidate it + if(mf_classic_is_key_found(data, i, MfClassicKeyA) && + data->block[i].value[0] == key) { + mf_classic_set_key_not_found(data, i, MfClassicKeyA); + is_key_a_found = false; + FURI_LOG_D(TAG, "Key %dA not found in attack", i); + } } if(!is_key_b_found) { is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); @@ -775,9 +781,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { } deactivated = true; } else { - mf_classic_set_key_not_found(data, i, MfClassicKeyB); - is_key_b_found = false; - FURI_LOG_D(TAG, "Key %dB not found in attack", i); + // If the key B is marked as found and matches the searching key, invalidate it + if(mf_classic_is_key_found(data, i, MfClassicKeyB) && + data->block[i].value[10] == key) { + mf_classic_set_key_not_found(data, i, MfClassicKeyB); + is_key_b_found = false; + FURI_LOG_D(TAG, "Key %dB not found in attack", i); + } } if(is_key_a_found && is_key_b_found) break; if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; From 474897d644047343b8bbf9fb21e00e727ed608c1 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Fri, 24 Mar 2023 23:07:42 +0000 Subject: [PATCH 04/16] Fix POCSAG pager RIC: text repetition (#172) --- applications/external/pocsag_pager/protocols/pocsag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/pocsag_pager/protocols/pocsag.c b/applications/external/pocsag_pager/protocols/pocsag.c index ca210c2a4..cc393ac5b 100644 --- a/applications/external/pocsag_pager/protocols/pocsag.c +++ b/applications/external/pocsag_pager/protocols/pocsag.c @@ -157,7 +157,7 @@ static bool pocsag_decode_message_word(SubGhzProtocolDecoderPocsag* instance, ui // Function called when current message got decoded, but other messages might follow static void pocsag_message_done(SubGhzProtocolDecoderPocsag* instance) { // append the message to the long-term storage string - furi_string_cat_printf( + furi_string_printf( instance->generic.result_ric, "\e#RIC: %" PRIu32 "\e# | ", instance->ric); furi_string_cat_str(instance->generic.result_ric, func_msg[instance->func]); if(instance->func != POCSAG_FUNC_ALERT1) { From 22406f8aca612270d1fa5a922f2a9e67e901cce0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 25 Mar 2023 07:04:28 +0300 Subject: [PATCH 05/16] MF Classic dict - Fix key delete, now works properly --- lib/nfc/helpers/mf_classic_dict.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c index 93098d409..7bdfa9e78 100644 --- a/lib/nfc/helpers/mf_classic_dict.c +++ b/lib/nfc/helpers/mf_classic_dict.c @@ -330,17 +330,20 @@ bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) { uint32_t index = 0; bool key_removed = false; + stream_rewind(dict->stream); while(!key_removed) { if(!stream_read_line(dict->stream, next_line)) break; if(furi_string_get_char(next_line, 0) == '#') continue; if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; if(index++ != target) continue; - stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); - if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; + stream_seek(dict->stream, -(NFC_MF_CLASSIC_KEY_LEN + 1), StreamOffsetFromCurrent); + if(!stream_delete(dict->stream, (NFC_MF_CLASSIC_KEY_LEN + 1))) break; dict->total_keys--; key_removed = true; } + stream_rewind(dict->stream); + furi_string_free(next_line); return key_removed; } From 6e507df2b9f6d5b3dbdb6277dfb0812e7d7a79e8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 25 Mar 2023 07:44:40 +0300 Subject: [PATCH 06/16] Update readme and changelog --- CHANGELOG.md | 18 ++++-------------- ReadMe.md | 8 ++++---- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20dd09d50..625ae2bf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,8 @@ ### New changes -* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! -* Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch` -* App Loader: Add option to ignore api mismatch (warning! some apps WILL not work, please update them to avoid any issues) -> (by @Willy-JL | PR #395) -* SubGHz: Add manually -> GSN protocol support -* SubGHz: Add 318 and 418 MHz back to hopping list -* SubGHz: Fix hopper stuck at 433.42 due to wide range signals - -When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 -* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -> BadBT Support -* OFW: Screen streaming improvements -* OFW: 1-Wire Overdrive Mode -> **Breaking API change, api was changed from 19.x to 20.x** -* OFW: Disable UART IRQs by default -* OFW: BadUSB: implement boot protocol -* OFW: Remove hmac_sha256 from public API -> **Breaking API change, api was changed from 18.x to 19.x** -**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** +* NFC: MF Classic User Dict -> Fix deleting of the key in extra actions menu +* Plugins: Fix POCSAG pager `RIC:` text repetition and overlap (by @Willy-JL | PR #398) +* OFW: NFC: MF Classic - Additional checks before invalidating the key (Fixes issues with not using MF keys from user dict) +* OFW: Fix crash when emulating a DSGeneric key #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/ReadMe.md b/ReadMe.md index edaa9b152..871662933 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -52,9 +52,9 @@ Our Discord Community: - Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) - Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) - Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) -* Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes -* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu -* Sub-GHz -> External CC1101 module support +* Sub-GHz -> Short press OK in frequency analyzer to save detected frequency for usage in Read modes +* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu and automatically use selected frequency +* Sub-GHz -> External CC1101 module support (Hardware SPI used) * SubGHz -> **Hold right in received signal list to delete selected signal** * SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0** - now you can use arrow buttons to send signal with different button code * SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) @@ -87,7 +87,7 @@ Encoders/sending made by Eng1n33r & @xMasterX: - CAME Atomo - Nice Flor S - FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)] -- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] +- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) - Security+ v1 & v2 - Star Line From 001e00d84a826512bab69fd43a2564bec72c0316 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 26 Mar 2023 14:59:21 +0300 Subject: [PATCH 07/16] fbt format, aprimatic fixes --- .../external/pocsag_pager/protocols/pocsag.c | 3 +- .../totp_scene_generate_token.c | 7 +- applications/main/fap_loader/fap_loader_app.c | 11 +- assets/resources/subghz/assets/keeloq_mfcodes | 110 +++++++++--------- .../subghz/assets/setting_user.example | 2 +- .../targets/f7/furi_hal/furi_hal_subghz.c | 4 +- 6 files changed, 73 insertions(+), 64 deletions(-) diff --git a/applications/external/pocsag_pager/protocols/pocsag.c b/applications/external/pocsag_pager/protocols/pocsag.c index cc393ac5b..0296a70a7 100644 --- a/applications/external/pocsag_pager/protocols/pocsag.c +++ b/applications/external/pocsag_pager/protocols/pocsag.c @@ -157,8 +157,7 @@ static bool pocsag_decode_message_word(SubGhzProtocolDecoderPocsag* instance, ui // Function called when current message got decoded, but other messages might follow static void pocsag_message_done(SubGhzProtocolDecoderPocsag* instance) { // append the message to the long-term storage string - furi_string_printf( - instance->generic.result_ric, "\e#RIC: %" PRIu32 "\e# | ", instance->ric); + furi_string_printf(instance->generic.result_ric, "\e#RIC: %" PRIu32 "\e# | ", instance->ric); furi_string_cat_str(instance->generic.result_ric, func_msg[instance->func]); if(instance->func != POCSAG_FUNC_ALERT1) { furi_string_cat(instance->done_msg, instance->msg); diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 9e8b21d09..a8e93bbff 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -373,7 +373,8 @@ bool totp_scene_generate_token_handle_event( SceneState* scene_state; if(event->input.type == InputTypeLong) { - if(event->input.key == InputKeyDown && plugin_state->automation_method & AutomationMethodBadUsb) { + if(event->input.key == InputKeyDown && + plugin_state->automation_method & AutomationMethodBadUsb) { scene_state = (SceneState*)plugin_state->current_scene_state; totp_usb_type_code_worker_notify( scene_state->usb_type_code_worker_context, TotpUsbTypeCodeWorkerEventType); @@ -383,7 +384,9 @@ bool totp_scene_generate_token_handle_event( return true; } #ifdef TOTP_BADBT_TYPE_ENABLED - else if(event->input.key == InputKeyUp && plugin_state->automation_method & AutomationMethodBadBt) { + else if( + event->input.key == InputKeyUp && + plugin_state->automation_method & AutomationMethodBadBt) { scene_state = (SceneState*)plugin_state->current_scene_state; totp_bt_type_code_worker_notify( plugin_state->bt_type_code_worker_context, TotpBtTypeCodeWorkerEventType); diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index d85eb784b..f4f2550da 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -86,9 +86,16 @@ static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch) if(preload_res == FlipperApplicationPreloadStatusApiMismatch) { if(!ignore_mismatch) { DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "API Mismatch", 64, 0, AlignCenter, AlignTop); + dialog_message_set_header( + message, "API Mismatch", 64, 0, AlignCenter, AlignTop); dialog_message_set_buttons(message, "Cancel", NULL, "Continue"); - dialog_message_set_text(message, "This app might not\nwork correctly\nContinue anyways?", 64, 32, AlignCenter, AlignCenter); + dialog_message_set_text( + message, + "This app might not\nwork correctly\nContinue anyways?", + 64, + 32, + AlignCenter, + AlignCenter); if(dialog_message_show(loader->dialogs, message) == DialogMessageButtonRight) { retry = true; } diff --git a/assets/resources/subghz/assets/keeloq_mfcodes b/assets/resources/subghz/assets/keeloq_mfcodes index cb80c2e2e..e65eb0868 100644 --- a/assets/resources/subghz/assets/keeloq_mfcodes +++ b/assets/resources/subghz/assets/keeloq_mfcodes @@ -1,58 +1,58 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: AB 0B A1 23 45 FE E7 06 66 73 21 67 97 12 3D 61 -CA9DC3E30069ED9C257FCA6747136F617F4E390F2B8BDDFDEBEC8A398A6A0C1E -78F18401572E33117850EA83D00C2F92376E88D7CAC0BF7CBA7037BF6755F43C -909055FF43224057BCE5F965174AF46586EB7CA4CAE1B3EB8B66EA569047948A -AB9B7D338457774713147BF666A5996926B90146CB698AC2F4DE63ADE89D84BB -ED796AED9BB3185ACD94779F7CC42665D4A3B04419E4272B77DA8D94B5CF84921889CEB110AB55D7267720A7C5B290EF -88E0CECA92549C73981F95999FA8F03B1B2EB98774134752556D7D7EFA802757 -C42CABAD74010E35726659C8E4AF4888282FBEA9703616B3403DA7C3DCA8A8ED -6F44BC56AC2E9883A2469C1909D171A8C58A0CFE4B506CC562EB2F08A484AE1B -65DEBEBC629FA3CE72B5028E1E385DFFEE0A9FE227FC5F6DD4368C0CB1886A7D -EA9BDC762FCBAAA11A4BE677AE344993990153C9E7A4A89F8271F49765FC72EF -8FAE9AC3033E637703626956F91791DAE4B3BEA9C82C065C91A314DDB647F8FE661750526E58C613000260675C2B520C -3D853DEC62375B3201B1C2269E31794A3C29958B191953A331D39675CCB53C002EF1491B63C49E629AF5D747CC52BD11 -61A02BB85B08AA8047EAD9FB80D489AB15CBE0302C660891C4B29D2621C80DBB -5230A9651D1A0910695593E1A5F6EA6EB21990D6465E52B325CF141C9E0C9172 -C9348D18DC019C3E364F7AD9CD5B6D77EE2D6486CFBDFAFE7042AB917E8FFE7C -DED385BBAC8FAB5918DBDBDC8622850048A540963AF35C3DD772926927B148C2 -E1EC13990BDA8E22F2848F97069462FB46840FEA688C52EDE930CD22C4E6F445BF317A96C4A6C2DC4295B2E3E86053B9 -D5453884C337587A13117F35219C7B4356E8E63EBC4C197CC1633D444D0A6AD0 -72C3E291DA11AD3D195C6A1B65849B0C91B7D18762B515A5728389356C42B62C -0E9EA0D97053752977D83A019A2F0393D326407AE507F5EE6E650082DBC683F81BDD71B79BE81EEB3139815377577346 -A32FF38450B3121CB01CE06AA369DC7B883CD9B1695CBADBC9609F009D6BFF7B7518D9DD690D214A1DB0D1A0C6F9FC3F -98848EFBB09D2A3EA59EE91B1B510BA3775E36B14500DE1238317AFC9872358F -E8B2785366399F84EADF07B0E299603BB885780E6ECA883508FFB7664C6473FE -1F6CEA6696B2E07FEB256506609D7E11D9F09F18B9EE43DE9BC42014ABF5213F -F2FF5045A5E90AAF92C2ECCB9FEFFBDE400A7E3E6B09CF43608896F7BC91736F -73CC30A78808BB2B3F7F398D88C79470AF86B825DE0C2FF31442D351C2826D9C -B68FD5017BA4809AD22DF64805DCE329A81C2CE3F7BE87FADFBD02211AB02321 -57BC2E14A724D6E2F4B0FD9401C3E6E5117D338077958648A558E40C553C787F -882A41BC36393F06C57ED71E66D003E24B5DAE86F90D8AEDD89A2DFED6719BF1 -95EDC3C3EB639AC66656B58D8F71A5B1B329002C4CCF7666C41C717A939C0979 -494A32528A68F5B4DF45385CC7FB470224F25D8AC9C81AB0DBD291AA4764BB17 -9A6D21675317433CE6EE860C9A2713265E1DA5E8F4024690252971EA5C2A566A -2B8379BCDDD0E6F73B1AD2D5A4D69D34D0013E98C87AD2BCE7AEED80F3BF4F69 -6E5D67B8B825943F9B9979D5E1EA9348B1DD40A5DA39B20FA96B78CAD3E03747 -27559A18DD6D52FFED8427376113C1A35840D64A53466071E1B769A28F161A99 -A2F38E38C253947816B5E629AAC02BC77EF7B56CC95FBF291C05466C56E01E47FE92053C900C0F6F98B11D7873BB9AFC -8A7E57E1228F75F78D51C13FE79C269E43F007E55F5B87741BCADDAAA6402DF7 -E088817700DBC7D778427464368D7771E3C20194CE60D08668578CAA527258B8 -3E5AD04DE23578A3BBC5FB91608435EBA1FF1465EDCE3E064F60A2EED35C9015 -647C9BFB61C0509D152A7B6B5C548DC558052F862314B42F4D1D8B98F6BF2412 -3D659FF6999401CAB590681036C3FDABAF157C774928E0D7D76FAC08AA6CFE93 -342362E28923E64DC5047E25E5A2F3FC8A6EB63554793CB8A1C99FFE632A370508CA208CA912470DB343A1636C751B9E -3B71D04AB09DFB44015F5553B4B76C9419C4D615F60184BA0B6A5687E47D66BA -14CF7621A4943DE2156AB8FDE8A9E74D26776D8362D9364387626488CB3DA5DC -2F9205BF8B310C33E38F571FFBDF6FC4BA5135457A2CF6CA9CD319F3EDF4BF6E -785EDF05A2111B8E4A126BE274C9BD8D6C0482F4A2B716FFAE93EDB8D1634F41 -4B26880D1AE8EC1D285296F473EB5A805CF1C1EA47B899A6A3F8E9EFDB2CBCA3 -A002B3ED0D1FCBC02298BFE7F18207CD58AB21D358F20855D067939EF50DCC08 -BE82806DE526A6453C6FA309DAE0B52D67A98A194753DD4CC2C8C196A47B253F60149FAF49D0396E1F24CB1EDF1430DA -031686817FB37936FD0313B9358FD35BAF5DEB924F7A939C4B843DD095F11806 -3A7B7A7AE8723C2A060FF368AB048A48737D4EEAD3C97BF98BC9E8CAE552431B -357C4A1A41F43100208863F2E607AE14CC55235D757CDE5C491BE405BB72BDB4 -0C46E442B9AC3C479C18D4D94AB3E5124D4033AFD05AE00AC6881DD62F11E07F -8705CF1D9B202056CEBD98FF25CB0B6BF40175DBDC2FE86FE2A7D2AC796F818EA71A8C1312E9C7FCE6CC3D11FBBA98E4 +IV: AF 0B A3 13 56 FA F7 46 76 78 25 28 34 16 3D 62 +77995F096640A6CA8735DE839975FA3573145DDB995E45F58AECCD6A6F2D6FCB +A062DD58F9957EC098075344DFF69FB3B2A3C9893D4240C74BE32299F330290B +2AD2CCC4FB760D772001A903A995435260F442152BDCD5B075FBC61015BEC7E1 +34AE78CF87A10211C8E6F6E2EE18C4F0BBE3B677094B7118E03AD9E89AF70E28 +41943E7507D37A344F56EDF4BBDCDA75FAA10A6E97DF801ACF2A0E97E41782053CA74E31E3488EA1AFE29369E7A542C7 +9FA67B118BC1FE289F38A78DA4E1FFBAEB4498404B49CBD9690B9421FC05564D +3A872E97A668C644D3827273ADDA6B1BC689A3AD09F5980EC7461E40624653BE +5E1F4D865E5F4176DBF7832992B60947812E05701E647CF36427C2EE04F97FE2 +7FCF6E437D0DA231A2937C46622C4939F0045AEF5CF7FCF5D97E24B67995F0D3 +D09F230FEDB9CB690B5AC7C6BCE86B0779D9C233D2823562EABE340FF06C819D +84F0A81ABB7857438BF52BE8988C1A471EFEDFE16EC11851BFC39F34EB26236F318CFAAEC9A53AD5500D48CAE21E777A +F3FDDDD5DB6038D0E2FC02750530325976ADA2600DE19BF736AF6CB7E810D7627B4F396963F0288F486182228B9AAE22 +87E07B23B3B2740D93C82696C020057CC7F3864ABD6E6967656F44427C529DD1 +20C35809F7F5161C21E643A606DC48A5CC85BCEB546A03023DF778C4499426E3 +81CCF1CA68E2B6663DA9D12FEE241307A2E449440901793A955CB5D5915819DD +1B66D0664451153D0124364834E1543960A756351330523C3FFE83DA4EE7F0E6 +7025D550A40466B472BA71F3248C37E6DE1FD59ED5C11CBB26238795DD44F4B21BD447F3CA72AED6A25B977982100A1E +99F38C3F7C89D2805FB36F931AC5D1B248A56838AC29E13B1255CAE706B68216 +D138C616E4E1F6053177118C94F65C0BA6B155286CE63E0728E3F2D2BF6C6A98 +276E646DBF54B341F93AB4E1C36525AF983879F7251D84BB02DD54F4A5E0FA85A3278891F7ADA9ADE2F8AAD010F6F6D4 +3F3598143FE40E04FE25EADE1EC2B4CDAE339AF7730AE9DC45C97C0E44B299DBCC0E9DA6F4B0EE00F25D2FDD9E1C6BF5 +20FA8F62628FEA51A584CE298F22E60FF85BFE193AF1C5DE57605FF02E90739C +B14B4896088EF58E0CE659511C93782FB5F94BC69B64E5011EBD10DF18FFB3B1 +90BBE045FFEA06A77B55B0B6D0CFA8F12C4E1B35FB0111DD0C2CF1637AE8924A +04B87BC1D09E8EE3C8A91CE75169546D37868B2D87BF2D712623F84937ACE974 +B8C5B04070FFB27B4686057C57F762FA3CAF2BBD3E5BEBE462C1C2FC283AE118 +A40B154CEC2F5F989CA6F30703A0133217530D41F12739B25E2C1BEF54E6AC7C +4F5B9A68E8DEDB00410F5AD7FB7F7CA8F43B75F0457DA2AFAA8279A8C4AF34AB +9A7B185F6A157B1886DC6AA98B1F3D6899331D8BDDBAAC9620321E16BB4CC7E8 +4A710E11F1C7A7138065801BDB4E72B07608220BBCF7455111FDD41DC0290B94 +3A5B715089F926049077172755B0C48B4A4420031787D7DB113CF402C7D3D0AE +EE0B90EC27EC0F4A8DCD3C747E17594E0A27A92E05F2DE7B0457873C7154E075 +0B9B201C209072676A47225BE4E43B4631B080A85F9FCFAA5683A4F9A727187A +13A15C606AA2EA40F2DCDE7F44217F02D2D9796CAC9164100B211D7A22CF333B +DF5292BBF35AB1408956D439A81EF12F53573F985489727A10FB652B7BD8B10D +50E59C9DD3A08EA8752656B753B8D9D2BFD674EB4C5F0DCAE9870E81D7F00F6AAC133FA7C7307FA197D551EE877F8CD7 +E173C1798596A31F697D63E0CCDDFAB14B1B1E299DD642102A7858ECC795CF1B +92D3326A93AA6B37041F219C8035F37A057C1B69BECA7881098BED2A49C58751 +27D17F007115734FA0F55F2BDF016ECE8DFA703FA6D61729456E95B78FC8AC29 +4FF7306A426B7DE021D59968FAEF3453F555A9A952D81C4008D5000513799DEA +660CB0D4634EABC6CAA9E321CB08FC0C8C8F6BAE0FAF0C10C1FCCBA93B68D9B4 +86D84C91BFBF0DE22088C0F5A8598A2C2807033E60BC11333E8D1A6188F043D5 +F3E0E8566E12ADBA44974A3CA1D6D60456649031DCAD4365D0AE80FEDBC80AAA106A9BAB39448CD62EF916A59ECA9579 +F4D6EB6D241B17CA0A9E73E93DA3B58B6B257CC0484FC92E285984A09FD4CEA9 +094265CB574E0C9B8954B3130A2017492B1149C3FB9239A6B690A9C7B6635E5A +BE67B61B2F99BAA4AF94B71CB5F2386417D5F3B187899222D2671B1147BA9932 +74840B34C9F27A76FCB593629C8114BCABD1B1CE96E22CC378DC9E7BEEF263FB +2511F44F0A13D94B55D7FF3297194E47D6987890F9170BCBC14A7607C5A38E01 +FD0CF9314CB9B949CEFE1DA3FA05A18FBEEF751B4DC900DBAE068EE211C4492C +22ECD6934472760CF806E7C9E86885D0C0AAE501EDBF9DCB7ADC7AE53F3B73C38F2B6FB3FD0F867C5B5BFD00440CB43A +325CA78241AE4EE784CC867815403E342F77BB428EB1FE189AD569F10170CB98 +BF065D29EC8E2BB411F0131DF3A06BDF07B1436A14004D0E11E1261F0E232CB8 +CE015802FCE9AFD9807F855D813FD06D5446A8953057A79BC4A452BDAB8E9DD7 +C6B569EB172EC4609966E2C9426BE99A86529073A57824B1752392658C4E87F08ED8675A32F44E413CD6037CA4A0DE71 diff --git a/assets/resources/subghz/assets/setting_user.example b/assets/resources/subghz/assets/setting_user.example index e0c474a99..5034659be 100644 --- a/assets/resources/subghz/assets/setting_user.example +++ b/assets/resources/subghz/assets/setting_user.example @@ -1,7 +1,7 @@ # to use manual settings and prevent them from being deleted on upgrade, rename *_user.example files to *_user Filetype: Flipper SubGhz Setting File Version: 1 -# Add Standard frequencies for your region +# Add Standard frequencies included with firmware and place user frequencies after them #Add_standard_frequencies: true # Default Frequency: used as default for "Read" and "Read Raw" diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 989f97698..ed9864ae9 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -119,7 +119,7 @@ bool furi_hal_subghz_check_radio(void) { if((ver != 0) && (ver != 255)) { FURI_LOG_D(TAG, "Radio check ok"); } else { - FURI_LOG_D(TAG, "Radio check failed"); + FURI_LOG_D(TAG, "Radio check failed, revert to default"); result = false; } @@ -182,7 +182,7 @@ bool furi_hal_subghz_init_check(void) { if(result) { FURI_LOG_I(TAG, "Init OK"); } else { - FURI_LOG_E(TAG, "Failed to initialization"); + FURI_LOG_E(TAG, "Selected CC1101 module init failed, revert to default"); } return result; } From ae9659d32dec51fc6e1d2a382b8119043f3fa012 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:28:13 +0300 Subject: [PATCH 08/16] [FL-3193] Additional checks before invalidating the key (#2533) --- lib/nfc/nfc_worker.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 4561ff2af..c2b89c71a 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -638,7 +638,8 @@ static void nfc_worker_mf_classic_key_attack( (uint32_t)key); if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); - FURI_LOG_D(TAG, "Key found"); + FURI_LOG_D( + TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); uint64_t found_key; @@ -661,7 +662,8 @@ static void nfc_worker_mf_classic_key_attack( (uint32_t)key); if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { mf_classic_set_key_found(data, i, MfClassicKeyB, key); - FURI_LOG_D(TAG, "Key found"); + FURI_LOG_D( + TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); } } @@ -760,9 +762,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { furi_hal_nfc_sleep(); deactivated = true; } else { - mf_classic_set_key_not_found(data, i, MfClassicKeyA); - is_key_a_found = false; - FURI_LOG_D(TAG, "Key %dA not found in attack", i); + // If the key A is marked as found and matches the searching key, invalidate it + if(mf_classic_is_key_found(data, i, MfClassicKeyA) && + data->block[i].value[0] == key) { + mf_classic_set_key_not_found(data, i, MfClassicKeyA); + is_key_a_found = false; + FURI_LOG_D(TAG, "Key %dA not found in attack", i); + } } if(!is_key_b_found) { is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); @@ -775,9 +781,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { } deactivated = true; } else { - mf_classic_set_key_not_found(data, i, MfClassicKeyB); - is_key_b_found = false; - FURI_LOG_D(TAG, "Key %dB not found in attack", i); + // If the key B is marked as found and matches the searching key, invalidate it + if(mf_classic_is_key_found(data, i, MfClassicKeyB) && + data->block[i].value[10] == key) { + mf_classic_set_key_not_found(data, i, MfClassicKeyB); + is_key_b_found = false; + FURI_LOG_D(TAG, "Key %dB not found in attack", i); + } } if(is_key_a_found && is_key_b_found) break; if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; From 27341fc1934ee309ee2ba1a2a42322449a12d7f4 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 27 Mar 2023 16:39:24 +0900 Subject: [PATCH 09/16] Fix typo in fbt.md (#2539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit availabe -> available Co-authored-by: あく --- documentation/fbt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/fbt.md b/documentation/fbt.md index a47174631..65729c5c8 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -72,7 +72,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio - `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `OPENOCD_ADAPTER_SERIAL=...`. - `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs. - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests. -- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be availabe on your system's `PATH`. +- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be available on your system's `PATH`. - `cli` - start a Flipper CLI session over USB. ### Firmware targets From 130181614a8265d0307e1fda4512c9ee4893838a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 27 Mar 2023 23:10:45 +0300 Subject: [PATCH 10/16] Aprimatic emulation support testing thats was hard! --- lib/subghz/protocols/keeloq.c | 68 ++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index d08352e78..c5d8fe343 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -88,7 +88,7 @@ static const char* mfname; static uint8_t kl_type; static uint8_t btn_temp_id; static uint8_t btn_temp_id_original; -static bool bft_prog_mode; +static uint8_t klq_prog_mode; static uint16_t temp_counter; void keeloq_set_btn(uint8_t b) { @@ -106,7 +106,7 @@ uint8_t keeloq_get_custom_btn() { void keeloq_reset_original_btn() { btn_temp_id_original = 0; temp_counter = 0; - bft_prog_mode = false; + klq_prog_mode = 0; } void keeloq_reset_mfname() { @@ -173,16 +173,27 @@ static bool subghz_protocol_keeloq_gen_data( // BFT programming mode on / off conditions if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) { - bft_prog_mode = true; + klq_prog_mode = 1; } - if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) { - bft_prog_mode = false; + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && (klq_prog_mode == 1)) { + klq_prog_mode = 0; + } + // Aprimatic programming mode on / off conditions + if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn == 0xF)) { + klq_prog_mode = 2; + } + if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn != 0xF) && + (klq_prog_mode == 2)) { + klq_prog_mode = 0; } // If we using BFT programming mode we will trasmit its seed in hop part like original remote - if(bft_prog_mode) { + if(klq_prog_mode == 1) { hop = instance->generic.seed; + } else if(klq_prog_mode == 2) { + // If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :) + hop = 0x1A2B3C4D; } - if(counter_up && !bft_prog_mode) { + if(counter_up && klq_prog_mode == 0) { if(instance->generic.cnt < 0xFFFF) { if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { instance->generic.cnt = 0; @@ -193,11 +204,28 @@ static bool subghz_protocol_keeloq_gen_data( instance->generic.cnt = 0; } } - if(!bft_prog_mode) { + if(klq_prog_mode == 0) { uint32_t decrypt = (uint32_t)btn << 28 | (instance->generic.serial & 0x3FF) << 16 | //ToDo in some protocols the discriminator is 0 instance->generic.cnt; + + if(strcmp(instance->manufacture_name, "Aprimatic") == 0) { + // Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial + // Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test + // For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here + uint32_t apri_serial = instance->generic.serial; + uint8_t apr1 = 0; + for(uint16_t i = 1; i != 0b10000000000; i <<= 1) { + if(apri_serial & i) apr1++; + } + apri_serial &= 0b00001111111111; + if(apr1 % 2 == 0) { + apri_serial |= 0b110000000000; + } + decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt; + } + // DTM Neo, Came_Space uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) -> 12bit normal learning if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || @@ -363,11 +391,14 @@ static bool if(instance->manufacture_name == 0x0) { instance->manufacture_name = ""; } - if(bft_prog_mode) { + if(klq_prog_mode == 1) { instance->manufacture_name = "BFT"; + } else if(klq_prog_mode == 2) { + instance->manufacture_name = "Aprimatic"; } uint8_t klq_last_custom_btn = 0xA; - if(strcmp(instance->manufacture_name, "BFT") == 0) { + if((strcmp(instance->manufacture_name, "BFT") == 0) || + (strcmp(instance->manufacture_name, "Aprimatic") == 0)) { klq_last_custom_btn = 0xF; } @@ -649,7 +680,7 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->keystore = subghz_environment_get_keystore(environment); instance->manufacture_from_file = furi_string_alloc(); - bft_prog_mode = false; + klq_prog_mode = 0; return instance; } @@ -781,6 +812,13 @@ static inline bool subghz_protocol_keeloq_check_decrypt( if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) || ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) { instance->cnt = decrypt & 0x0000FFFF; + FURI_LOG_I( + "DED", + "btn: %d, decrypt: %lx, end_serial: %lx, serial: %lx", + btn, + decrypt, + end_serial, + instance->serial); return true; } return false; @@ -1151,7 +1189,7 @@ static void subghz_protocol_keeloq_check_remote_controller( uint32_t key_hop = key & 0x00000000ffffffff; // If we are in BFT programming mode we will set previous remembered counter and skip mf keys check - if(!bft_prog_mode) { + if(klq_prog_mode == 0) { // Check key AN-Motors if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { @@ -1168,10 +1206,14 @@ static void subghz_protocol_keeloq_check_remote_controller( } temp_counter = instance->cnt; - } else { + } else if(klq_prog_mode == 1) { *manufacture_name = "BFT"; mfname = *manufacture_name; instance->cnt = temp_counter; + } else if(klq_prog_mode == 2) { + *manufacture_name = "Aprimatic"; + mfname = *manufacture_name; + instance->cnt = temp_counter; } instance->serial = key_fix & 0x0FFFFFFF; From 0f06991391e728d3aab01f80e345b669cbafc3ee Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 27 Mar 2023 23:27:15 +0300 Subject: [PATCH 11/16] Aprimatic add manually --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../subghz/scenes/subghz_scene_set_type.c | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index f94b97659..364c82558 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -20,6 +20,7 @@ typedef enum { SubmenuIndexDTMNeo433, SubmenuIndexGibidi433, SubmenuIndexGSN, + SubmenuIndexAprimatic, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexNiceFlorS_433_92, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index ac177c0d0..85d905a6d 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -158,6 +158,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexGSN, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "KL: Aprimatic 433MHz", + SubmenuIndexAprimatic, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "KL: Elmes (PL) 433MHz", @@ -502,6 +508,32 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexAprimatic: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + (key & 0x000FFFFF) | 0x00600000, + 0x2, + 0x0003, + "Aprimatic", + subghz->txrx->preset); + flipper_format_write_string_cstr( + subghz->txrx->fff_data, "Manufacture", "Aprimatic"); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexGibidi433: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); From ce430ff7f6bbd326477d3e232895393cd688ff71 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Mar 2023 01:58:35 +0300 Subject: [PATCH 12/16] Remove debug, change aprimatic default button 4 --- applications/main/subghz/scenes/subghz_scene_set_type.c | 2 +- lib/subghz/protocols/keeloq.c | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 85d905a6d..536674dda 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -517,7 +517,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz->txrx->fff_data, (key & 0x000FFFFF) | 0x00600000, - 0x2, + 0x4, 0x0003, "Aprimatic", subghz->txrx->preset); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index c5d8fe343..ab021151d 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -812,13 +812,6 @@ static inline bool subghz_protocol_keeloq_check_decrypt( if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) || ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) { instance->cnt = decrypt & 0x0000FFFF; - FURI_LOG_I( - "DED", - "btn: %d, decrypt: %lx, end_serial: %lx, serial: %lx", - btn, - decrypt, - end_serial, - instance->serial); return true; } return false; From bb600218b6c0f8fcd163078c0c08a75bce4ab29d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Mar 2023 02:32:35 +0300 Subject: [PATCH 13/16] Alutech AT4N + AN-Motors AT4 - add manually --- .../main/subghz/helpers/subghz_custom_event.h | 2 + .../subghz/scenes/subghz_scene_set_type.c | 61 +++++++++++++++++++ lib/subghz/protocols/alutech_at_4n.c | 8 ++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 364c82558..eb0ed70e7 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -21,6 +21,8 @@ typedef enum { SubmenuIndexGibidi433, SubmenuIndexGSN, SubmenuIndexAprimatic, + SubmenuIndexANMotorsAT4, + SubmenuIndexAlutechAT4N, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexNiceFlorS_433_92, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 536674dda..b95eee8c9 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -98,6 +98,18 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexSomfyTelis, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "AN-Motors AT4 433MHz", + SubmenuIndexANMotorsAT4, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "Alutech AT4N 433MHz", + SubmenuIndexAlutechAT4N, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "KL: DoorHan 315MHz", @@ -508,6 +520,32 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexANMotorsAT4: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + (key & 0x00FFFFFF) | 0x04000000, + 0x2, + 0x0021, + "AN-Motors", + subghz->txrx->preset); + flipper_format_write_string_cstr( + subghz->txrx->fff_data, "Manufacture", "AN-Motors"); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexAprimatic: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); @@ -749,6 +787,29 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexAlutechAT4N: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_alutech_at_4n_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + (key & 0x000FFFFF) | 0x00100000, + 0x44, + 0x0003, + subghz->txrx->preset); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexSomfyTelis: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 7b1bd5e76..5c09e8bb8 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -320,8 +320,12 @@ bool subghz_protocol_alutech_at_4n_create_data( instance->generic.data_count_bit = 72; bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn); if(res) { - return SubGhzProtocolStatusOk == - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((res == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) { + FURI_LOG_E(TAG, "Unable to add CRC"); + res = false; + } } return res; } From 74ec9760daef761f50902217e02657fdc01ae63a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Mar 2023 03:41:27 +0300 Subject: [PATCH 14/16] Update readme, docs, changelog --- CHANGELOG.md | 2 ++ ReadMe.md | 3 +- documentation/SubGHzRemoteProg.md | 50 +++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 625ae2bf9..f94f117b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ### New changes +* SubGHz: AN-Motors AT4 + Alutech AT4N - Add Manually support +* SubGHz: Aprimatic keeloq emulation support + Add Manually * NFC: MF Classic User Dict -> Fix deleting of the key in extra actions menu * Plugins: Fix POCSAG pager `RIC:` text repetition and overlap (by @Willy-JL | PR #398) * OFW: NFC: MF Classic - Additional checks before invalidating the key (Fixes issues with not using MF keys from user dict) diff --git a/ReadMe.md b/ReadMe.md index 871662933..ecf693337 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -84,6 +84,7 @@ Encoders/sending made by Eng1n33r & @xMasterX: - Keeloq: Beninca - Keeloq: Stilmatic / Schellenberg - Keeloq: CAME Space +- Keeloq: Aprimatic (model TR and similar) - CAME Atomo - Nice Flor S - FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)] @@ -189,7 +190,7 @@ Games: ## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) -## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) +## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) ## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) diff --git a/documentation/SubGHzRemoteProg.md b/documentation/SubGHzRemoteProg.md index 5f453806e..a5357fe18 100644 --- a/documentation/SubGHzRemoteProg.md +++ b/documentation/SubGHzRemoteProg.md @@ -1,5 +1,55 @@ # How to use Flipper as a new SubGHz remote (not clone of original remote) +### If your system is not added here that doesn't mean flipper don't support it! Look into add manually menu, and search for your manufacturers inscturctions! +### Also many supported systems can be used only from `Read` mode, `Add Manually` is used only to make new remotes that can be binded with receiver + +## AN-Motors AT4 + +**This instruction for older boards, if your has no** `Learn` **button but has buttons** `F`, `CL`, `+`, `-` **read instruction from Alutech AT4N** +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> AN-Motors AT4 433Mhz +2. Open your new remote file +3. Open your receiver box, find button `Learn` click it one time, led will turn on. +4. Press `Send` on your flipper one time, led on receiver board will turn off. +5. Press `Send` on your flipper again, led on receiver will start flashing, wait couple seconds until led turns off. +6. Done + +Watch this video to learn more (video in Russian language): https://www.youtube.com/watch?v=URVMtTELcnU + +## Alutech AT4N (AN-Motors) + +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Alutech AT4N 433Mhz +2. Open your new remote file +3. Open your receiver box, find button `F` press it for ~3sec, display will show `Pr`. +4. Click `F` button couple times until you see `Lr` on screen +5. Using buttons `+` / `-` select free number that has no remotes in it (if it has remote programmed on that number, it will show a red dot on the down right corner) +6. Press `Send` on your flipper one time, display on receiver board will flash and red dot will appear next to remote number. +7. Press button `F` on receiver board for ~3sec to exit programming mode +8. Done + +Watch this video to learn more and see how different boards can be programmed (video in Russian language): https://www.youtube.com/watch?v=XrOVVYhFXDg + +## Aprimatic TR + +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> KL: Aprimatic 433Mhz +2. Open your new remote file +3. Push all 4 buttons at same time on your existing remote thats already works with receiver +4. Receiver makes a continuous beep +5. Press `Send` on your flipper for ~2 seconds +6. Wait until receiver stops beeping +7. Done? + +## Doorhan + +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> KL: Doorhan 433Mhz or 315Mhz depends on your receiver (find out by reading your existing remote) +2. Open your new remote file +3. Push `P` button for ~2 sec, led will start flashing +4. Press `Send` on your flipper for ~2 seconds +5. Led on the receiver board will flash and turn off +6. Done! + +Also you can program new remote using old remote on newer boards! See first video below: +Watch this videos to learn more (videos in Russian language): https://www.youtube.com/watch?v=wZ5121HYv50 / https://www.youtube.com/watch?v=1ucrDKF3vWc + ## Somfy Telis 1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Somfy Telis 433Mhz From 85d3ecb729c88ef71d21b738c2af6fba9104247f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Mar 2023 04:21:53 +0300 Subject: [PATCH 15/16] Update Wifi marauder --- .../wifi_marauder_companion/application.fam | 2 +- .../scenes/wifi_marauder_scene_config.h | 2 + .../wifi_marauder_scene_console_output.c | 44 +++-- .../scenes/wifi_marauder_scene_log_viewer.c | 185 ++++++++++++++++++ .../wifi_marauder_scene_settings_init.c | 130 ++++++++++++ .../scenes/wifi_marauder_scene_start.c | 41 +++- .../scenes/wifi_marauder_scene_text_input.c | 4 +- .../wifi_marauder_app.c | 52 +++++ .../wifi_marauder_app.h | 2 +- .../wifi_marauder_app_i.h | 28 ++- .../wifi_marauder_custom_event.h | 4 +- .../wifi_marauder_pcap.c | 37 +++- .../wifi_marauder_pcap.h | 11 +- .../wifi_marauder_uart.h | 2 +- 14 files changed, 515 insertions(+), 29 deletions(-) create mode 100644 applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_log_viewer.c create mode 100644 applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_settings_init.c diff --git a/applications/external/wifi_marauder_companion/application.fam b/applications/external/wifi_marauder_companion/application.fam index d8bfc58a6..66255706a 100644 --- a/applications/external/wifi_marauder_companion/application.fam +++ b/applications/external/wifi_marauder_companion/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="wifi_marauder_app", requires=["gui"], - stack_size=1 * 1024, + stack_size=4 * 1024, order=90, fap_icon="wifi_10px.png", fap_category="GPIO", diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h index 75e95c9bc..715897d17 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h @@ -1,3 +1,5 @@ ADD_SCENE(wifi_marauder, start, Start) ADD_SCENE(wifi_marauder, console_output, ConsoleOutput) ADD_SCENE(wifi_marauder, text_input, TextInput) +ADD_SCENE(wifi_marauder, settings_init, SettingsInit) +ADD_SCENE(wifi_marauder, log_viewer, LogViewer) diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c index 77beb733c..0729500eb 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c @@ -4,6 +4,11 @@ void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, vo furi_assert(context); WifiMarauderApp* app = context; + if(app->is_writing_log) { + app->has_saved_logs_this_session = true; + storage_file_write(app->log_file, buf, len); + } + // If text box store gets too big, then truncate it app->text_box_store_strlen += len; if(app->text_box_store_strlen >= WIFI_MARAUDER_TEXT_BOX_STORE_SIZE - 1) { @@ -21,15 +26,7 @@ void wifi_marauder_console_output_handle_rx_packets_cb(uint8_t* buf, size_t len, furi_assert(context); WifiMarauderApp* app = context; - // If it is a sniff function, open the pcap file for recording - if(strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0 && !app->is_writing) { - app->is_writing = true; - if(!app->capture_file || !storage_file_is_open(app->capture_file)) { - wifi_marauder_create_pcap_file(app); - } - } - - if(app->is_writing) { + if(app->is_writing_pcap) { storage_file_write(app->capture_file, buf, len); } } @@ -49,8 +46,7 @@ void wifi_marauder_scene_console_output_on_enter(void* context) { furi_string_reset(app->text_box_store); app->text_box_store_strlen = 0; if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) { - const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION - "\nby @0xchocolate\nmodified by @tcpassos\n"; + const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION "\n"; furi_string_cat_str(app->text_box_store, help_msg); app->text_box_store_strlen += strlen(help_msg); } @@ -62,7 +58,7 @@ void wifi_marauder_scene_console_output_on_enter(void* context) { } } - // Set starting text - for "View Log", this will just be what was already in the text box store + // Set starting text - for "View Log from end", this will just be what was already in the text box store text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store)); scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0); @@ -76,8 +72,23 @@ void wifi_marauder_scene_console_output_on_enter(void* context) { app->lp_uart, wifi_marauder_console_output_handle_rx_packets_cb); // setup callback for packets rx thread - // Send command with newline '\n' + // Get ready to send command if(app->is_command && app->selected_tx_string) { + // Create files *before* sending command + // (it takes time to iterate through the directory) + if(app->ok_to_save_logs) { + app->is_writing_log = true; + wifi_marauder_create_log_file(app); + } + + // If it is a sniff function, open the pcap file for recording + if(app->ok_to_save_pcaps && + strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0) { + app->is_writing_pcap = true; + wifi_marauder_create_pcap_file(app); + } + + // Send command with newline '\n' wifi_marauder_uart_tx( (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string)); wifi_marauder_uart_tx((uint8_t*)("\n"), 1); @@ -111,8 +122,13 @@ void wifi_marauder_scene_console_output_on_exit(void* context) { wifi_marauder_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n")); } - app->is_writing = false; + app->is_writing_pcap = false; if(app->capture_file && storage_file_is_open(app->capture_file)) { storage_file_close(app->capture_file); } + + app->is_writing_log = false; + if(app->log_file && storage_file_is_open(app->log_file)) { + storage_file_close(app->log_file); + } } diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_log_viewer.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_log_viewer.c new file mode 100644 index 000000000..f4e84ccc8 --- /dev/null +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_log_viewer.c @@ -0,0 +1,185 @@ +#include "../wifi_marauder_app_i.h" + +void wifi_marauder_scene_log_viewer_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + WifiMarauderApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +static void _read_log_page_into_text_store(WifiMarauderApp* app) { + char temp[64 + 1]; + storage_file_seek( + app->log_file, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE * (app->open_log_file_page - 1), true); + furi_string_reset(app->text_box_store); + for(uint16_t i = 0; i < (WIFI_MARAUDER_TEXT_BOX_STORE_SIZE / (sizeof(temp) - 1)); i++) { + uint16_t num_bytes = storage_file_read(app->log_file, temp, sizeof(temp) - 1); + if(num_bytes == 0) { + break; + } + temp[num_bytes] = '\0'; + furi_string_cat_str(app->text_box_store, temp); + } +} + +void wifi_marauder_scene_log_viewer_setup_widget(WifiMarauderApp* app, bool called_from_browse) { + Widget* widget = app->widget; + bool is_open = storage_file_is_open(app->log_file); + bool should_open_log = (app->has_saved_logs_this_session || called_from_browse); + if(is_open) { + _read_log_page_into_text_store(app); + } else if( + should_open_log && + storage_file_open(app->log_file, app->log_file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { + uint64_t filesize = storage_file_size(app->log_file); + app->open_log_file_num_pages = filesize / WIFI_MARAUDER_TEXT_BOX_STORE_SIZE; + int extra_page = (filesize % WIFI_MARAUDER_TEXT_BOX_STORE_SIZE != 0) ? 1 : 0; + app->open_log_file_num_pages = (filesize / WIFI_MARAUDER_TEXT_BOX_STORE_SIZE) + extra_page; + app->open_log_file_page = 1; + _read_log_page_into_text_store(app); + } else { + app->open_log_file_page = 0; + app->open_log_file_num_pages = 0; + } + + widget_reset(widget); + + if(furi_string_empty(app->text_box_store)) { + char help_msg[256]; + snprintf( + help_msg, + sizeof(help_msg), + "The log is empty! :(\nTry sending a command?\n\nSaving pcaps to flipper sdcard: %s\nSaving logs to flipper sdcard: %s", + app->ok_to_save_pcaps ? "ON" : "OFF", + app->ok_to_save_logs ? "ON" : "OFF"); + furi_string_set_str(app->text_box_store, help_msg); + } + + widget_add_text_scroll_element( + widget, 0, 0, 128, 53, furi_string_get_cstr(app->text_box_store)); + + if(1 < app->open_log_file_page && app->open_log_file_page < app->open_log_file_num_pages) { + // hide "Browse" text for middle pages + widget_add_button_element( + widget, GuiButtonTypeCenter, "", wifi_marauder_scene_log_viewer_widget_callback, app); + } else { + // only show "Browse" text on first and last page + widget_add_button_element( + widget, + GuiButtonTypeCenter, + "Browse", + wifi_marauder_scene_log_viewer_widget_callback, + app); + } + + char pagecounter[100]; + snprintf( + pagecounter, + sizeof(pagecounter), + "%d/%d", + app->open_log_file_page, + app->open_log_file_num_pages); + if(app->open_log_file_page > 1) { + if(app->open_log_file_page == app->open_log_file_num_pages) { + // only show left side page-count on last page + widget_add_button_element( + widget, + GuiButtonTypeLeft, + pagecounter, + wifi_marauder_scene_log_viewer_widget_callback, + app); + } else { + widget_add_button_element( + widget, GuiButtonTypeLeft, "", wifi_marauder_scene_log_viewer_widget_callback, app); + } + } + if(app->open_log_file_page < app->open_log_file_num_pages) { + widget_add_button_element( + widget, + GuiButtonTypeRight, + pagecounter, + wifi_marauder_scene_log_viewer_widget_callback, + app); + } +} + +void wifi_marauder_scene_log_viewer_on_enter(void* context) { + WifiMarauderApp* app = context; + + app->open_log_file_page = 0; + app->open_log_file_num_pages = 0; + bool saved_logs_exist = false; + if(!app->has_saved_logs_this_session && furi_string_empty(app->text_box_store)) { + // no commands sent yet this session, find last saved log + if(storage_dir_open(app->log_file, MARAUDER_APP_FOLDER_LOGS)) { + char name[70]; + char lastname[70]; + while(storage_dir_read(app->log_file, NULL, name, sizeof(name))) { + // keep reading directory until last file is reached + strlcpy(lastname, name, sizeof(lastname)); + saved_logs_exist = true; + } + if(saved_logs_exist) { + snprintf( + app->log_file_path, + sizeof(app->log_file_path), + "%s/%s", + MARAUDER_APP_FOLDER_LOGS, + lastname); + } + } + storage_dir_close(app->log_file); + } + + wifi_marauder_scene_log_viewer_setup_widget(app, saved_logs_exist); + + view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewWidget); +} + +bool wifi_marauder_scene_log_viewer_on_event(void* context, SceneManagerEvent event) { + WifiMarauderApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + // Browse + FuriString* predefined_filepath = furi_string_alloc_set_str(MARAUDER_APP_FOLDER_LOGS); + FuriString* selected_filepath = furi_string_alloc(); + if(dialog_file_browser_show( + app->dialogs, selected_filepath, predefined_filepath, NULL)) { + strncpy( + app->log_file_path, + furi_string_get_cstr(selected_filepath), + sizeof(app->log_file_path)); + if(storage_file_is_open(app->log_file)) { + storage_file_close(app->log_file); + } + wifi_marauder_scene_log_viewer_setup_widget(app, true); + } + furi_string_free(selected_filepath); + furi_string_free(predefined_filepath); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + // Advance page + ++app->open_log_file_page; + wifi_marauder_scene_log_viewer_setup_widget(app, false); + } else if(event.event == GuiButtonTypeLeft) { + // Previous page + --app->open_log_file_page; + wifi_marauder_scene_log_viewer_setup_widget(app, false); + } + } + + return consumed; +} + +void wifi_marauder_scene_log_viewer_on_exit(void* context) { + WifiMarauderApp* app = context; + widget_reset(app->widget); + if(storage_file_is_open(app->log_file)) { + storage_file_close(app->log_file); + } +} diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_settings_init.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_settings_init.c new file mode 100644 index 000000000..04d099d12 --- /dev/null +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_settings_init.c @@ -0,0 +1,130 @@ +#include "../wifi_marauder_app_i.h" + +const char* Y = "Y"; +const char* N = "N"; + +#define PROMPT_PCAPS 0 +#define PROMPT_LOGS 1 + +void wifi_marauder_scene_settings_init_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + WifiMarauderApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void wifi_marauder_scene_settings_init_setup_widget(WifiMarauderApp* app) { + Widget* widget = app->widget; + + widget_reset(widget); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "No", wifi_marauder_scene_settings_init_widget_callback, app); + widget_add_button_element( + widget, GuiButtonTypeRight, "Yes", wifi_marauder_scene_settings_init_widget_callback, app); + + if(app->which_prompt == PROMPT_PCAPS) { + widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Save pcaps?"); + widget_add_text_scroll_element( + widget, + 0, + 12, + 128, + 38, + "With compatible marauder\nfirmware, you can choose to\nsave captures (pcaps) to the\nflipper sd card here:\n" MARAUDER_APP_FOLDER_USER_PCAPS + "\n\nYou can change this setting in the app at any time. Would\nyou like to enable this feature now?"); + } else { + widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Save logs?"); + widget_add_text_scroll_element( + widget, + 0, + 12, + 128, + 38, + "This app supports saving text\nlogs of console output to the\nflipper sd card here:\n" MARAUDER_APP_FOLDER_USER_LOGS + "\n\nYou can change this setting in the app at any time. Would\nyou like to enable this feature now?"); + } +} + +void wifi_marauder_scene_settings_init_on_enter(void* context) { + WifiMarauderApp* app = context; + + app->which_prompt = PROMPT_PCAPS; + wifi_marauder_scene_settings_init_setup_widget(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewWidget); +} + +bool wifi_marauder_scene_settings_init_on_event(void* context, SceneManagerEvent event) { + WifiMarauderApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + // get which button press: "Yes" or "No" + if(event.event == GuiButtonTypeRight) { + // Yes + if(app->which_prompt == PROMPT_PCAPS) { + app->ok_to_save_pcaps = true; + } else { + app->ok_to_save_logs = true; + } + } else if(event.event == GuiButtonTypeLeft) { + // No + if(app->which_prompt == PROMPT_PCAPS) { + app->ok_to_save_pcaps = false; + } else { + app->ok_to_save_logs = false; + } + } + + // save setting to file, load next widget or scene + if(app->which_prompt == PROMPT_PCAPS) { + if(storage_file_open( + app->save_pcap_setting_file, + SAVE_PCAP_SETTING_FILEPATH, + FSAM_WRITE, + FSOM_CREATE_ALWAYS)) { + const char* ok = app->ok_to_save_pcaps ? Y : N; + storage_file_write(app->save_pcap_setting_file, ok, sizeof(ok)); + } else { + dialog_message_show_storage_error(app->dialogs, "Cannot save settings"); + } + storage_file_close(app->save_pcap_setting_file); + // same scene, different-looking widget + app->which_prompt = PROMPT_LOGS; + wifi_marauder_scene_settings_init_setup_widget(app); + } else { + if(storage_file_open( + app->save_logs_setting_file, + SAVE_LOGS_SETTING_FILEPATH, + FSAM_WRITE, + FSOM_CREATE_ALWAYS)) { + const char* ok = app->ok_to_save_logs ? Y : N; + storage_file_write(app->save_logs_setting_file, ok, sizeof(ok)); + } else { + dialog_message_show_storage_error(app->dialogs, "Cannot save settings"); + } + storage_file_close(app->save_logs_setting_file); + // go back to start scene (main menu) + app->need_to_prompt_settings_init = false; + scene_manager_previous_scene(app->scene_manager); + } + consumed = true; + } + + return consumed; +} + +void wifi_marauder_scene_settings_init_on_exit(void* context) { + WifiMarauderApp* app = context; + widget_reset(app->widget); + if(storage_file_is_open(app->save_pcap_setting_file)) { + storage_file_close(app->save_pcap_setting_file); + } + if(storage_file_is_open(app->save_logs_setting_file)) { + storage_file_close(app->save_logs_setting_file); + } +} diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c index df759bd15..2b2ee3a8a 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c @@ -127,6 +127,13 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = { {"Update", {"ota", "sd"}, 2, {"update -w", "update -s"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP}, {"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP}, {"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP}, + {"Save to flipper sdcard", // keep as last entry or change logic in callback below + {""}, + 1, + {""}, + NO_ARGS, + FOCUS_CONSOLE_START, + NO_TIP}, }; static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uint32_t index) { @@ -136,6 +143,13 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin furi_assert(index < NUM_MENU_ITEMS); const WifiMarauderItem* item = &items[index]; + if(index == NUM_MENU_ITEMS - 1) { + // "Save to flipper sdcard" special case - start SettingsInit widget + view_dispatcher_send_custom_event( + app->view_dispatcher, WifiMarauderEventStartSettingsInit); + return; + } + const int selected_option_index = app->selected_option_index[index]; furi_assert(selected_option_index < item->num_options_menu); app->selected_tx_string = item->actual_commands[selected_option_index]; @@ -147,6 +161,12 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin item->focus_console; app->show_stopscan_tip = item->show_stopscan_tip; + if(!app->is_command && selected_option_index == 0) { + // View Log from start + view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartLogViewer); + return; + } + bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) : item->needs_keyboard; if(needs_keyboard) { @@ -193,6 +213,11 @@ void wifi_marauder_scene_start_on_enter(void* context) { var_item_list, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneStart)); view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewVarItemList); + + // Wait, if the user hasn't initialized sdcard settings, let's prompt them once (then come back here) + if(app->need_to_prompt_settings_init) { + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneSettingsInit); + } } bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -204,16 +229,28 @@ bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) if(event.event == WifiMarauderEventStartKeyboard) { scene_manager_set_scene_state( app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); - scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewTextInput); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneTextInput); } else if(event.event == WifiMarauderEventStartConsole) { scene_manager_set_scene_state( app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); - scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); + } else if(event.event == WifiMarauderEventStartSettingsInit) { + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneSettingsInit); + } else if(event.event == WifiMarauderEventStartLogViewer) { + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneLogViewer); } consumed = true; } else if(event.type == SceneManagerEventTypeTick) { app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list); consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + consumed = true; } return consumed; diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c index ac8b15a2d..b721e868d 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c @@ -80,7 +80,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev if(event.event == WifiMarauderEventStartConsole) { // Point to custom string to send app->selected_tx_string = app->text_input_store; - scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); consumed = true; } else if(event.event == WifiMarauderEventSaveSourceMac) { if(12 != strlen(app->text_input_store)) { @@ -138,7 +138,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev app->special_case_input_src_addr, app->special_case_input_dst_addr); app->selected_tx_string = app->text_input_store; - scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); } consumed = true; } diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.c b/applications/external/wifi_marauder_companion/wifi_marauder_app.c index 7563d927a..a5521d49a 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -28,6 +28,9 @@ WifiMarauderApp* wifi_marauder_app_alloc() { app->dialogs = furi_record_open(RECORD_DIALOGS); app->storage = furi_record_open(RECORD_STORAGE); app->capture_file = storage_file_alloc(app->storage); + app->log_file = storage_file_alloc(app->storage); + app->save_pcap_setting_file = storage_file_alloc(app->storage); + app->save_logs_setting_file = storage_file_alloc(app->storage); app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&wifi_marauder_scene_handlers, app); @@ -65,6 +68,17 @@ WifiMarauderApp* wifi_marauder_app_alloc() { view_dispatcher_add_view( app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input)); + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, WifiMarauderAppViewWidget, widget_get_view(app->widget)); + + app->has_saved_logs_this_session = false; + + // if user hasn't confirmed whether to save pcaps and logs to sdcard, then prompt when scene starts + app->need_to_prompt_settings_init = + (!storage_file_exists(app->storage, SAVE_PCAP_SETTING_FILEPATH) || + !storage_file_exists(app->storage, SAVE_LOGS_SETTING_FILEPATH)); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneStart); return app; @@ -76,6 +90,38 @@ void wifi_marauder_make_app_folder(WifiMarauderApp* app) { if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER)) { dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder"); } + + if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_PCAPS)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder"); + } + + if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_LOGS)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder"); + } +} + +void wifi_marauder_load_settings(WifiMarauderApp* app) { + if(storage_file_open( + app->save_pcap_setting_file, + SAVE_PCAP_SETTING_FILEPATH, + FSAM_READ, + FSOM_OPEN_EXISTING)) { + char ok[1]; + storage_file_read(app->save_pcap_setting_file, ok, sizeof(ok)); + app->ok_to_save_pcaps = ok[0] == 'Y'; + } + storage_file_close(app->save_pcap_setting_file); + + if(storage_file_open( + app->save_logs_setting_file, + SAVE_LOGS_SETTING_FILEPATH, + FSAM_READ, + FSOM_OPEN_EXISTING)) { + char ok[1]; + storage_file_read(app->save_logs_setting_file, ok, sizeof(ok)); + app->ok_to_save_logs = ok[0] == 'Y'; + } + storage_file_close(app->save_logs_setting_file); } void wifi_marauder_app_free(WifiMarauderApp* app) { @@ -85,10 +131,15 @@ void wifi_marauder_app_free(WifiMarauderApp* app) { view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewVarItemList); view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput); view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewTextInput); + view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewWidget); + widget_free(app->widget); text_box_free(app->text_box); furi_string_free(app->text_box_store); text_input_free(app->text_input); storage_file_free(app->capture_file); + storage_file_free(app->log_file); + storage_file_free(app->save_pcap_setting_file); + storage_file_free(app->save_logs_setting_file); // View dispatcher view_dispatcher_free(app->view_dispatcher); @@ -118,6 +169,7 @@ int32_t wifi_marauder_app(void* p) { WifiMarauderApp* wifi_marauder_app = wifi_marauder_app_alloc(); wifi_marauder_make_app_folder(wifi_marauder_app); + wifi_marauder_load_settings(wifi_marauder_app); wifi_marauder_app->uart = wifi_marauder_usart_init(wifi_marauder_app); wifi_marauder_app->lp_uart = wifi_marauder_lp_uart_init(wifi_marauder_app); diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 92dd1dbd9..89a06f904 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.1" +#define WIFI_MARAUDER_APP_VERSION "v0.3.3" typedef struct WifiMarauderApp WifiMarauderApp; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 1165c6d9d..39b48fae3 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -14,16 +14,24 @@ #include #include #include +#include #include #include -#define NUM_MENU_ITEMS (16) +#define NUM_MENU_ITEMS (17) #define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096) #define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512) -#define MARAUDER_APP_FOLDER EXT_PATH("apps_data/marauder") +#define MARAUDER_APP_FOLDER_USER "apps_data/marauder" +#define MARAUDER_APP_FOLDER EXT_PATH(MARAUDER_APP_FOLDER_USER) +#define MARAUDER_APP_FOLDER_PCAPS MARAUDER_APP_FOLDER "/pcaps" +#define MARAUDER_APP_FOLDER_LOGS MARAUDER_APP_FOLDER "/logs" +#define MARAUDER_APP_FOLDER_USER_PCAPS MARAUDER_APP_FOLDER_USER "/pcaps" +#define MARAUDER_APP_FOLDER_USER_LOGS MARAUDER_APP_FOLDER_USER "/logs" +#define SAVE_PCAP_SETTING_FILEPATH MARAUDER_APP_FOLDER "/save_pcaps_here.setting" +#define SAVE_LOGS_SETTING_FILEPATH MARAUDER_APP_FOLDER "/save_logs_here.setting" struct WifiMarauderApp { Gui* gui; @@ -37,9 +45,21 @@ struct WifiMarauderApp { TextInput* text_input; Storage* storage; File* capture_file; + File* log_file; + char log_file_path[100]; + File* save_pcap_setting_file; + File* save_logs_setting_file; + bool need_to_prompt_settings_init; + int which_prompt; + bool ok_to_save_pcaps; + bool ok_to_save_logs; + bool has_saved_logs_this_session; DialogsApp* dialogs; VariableItemList* var_item_list; + Widget* widget; + int open_log_file_page; + int open_log_file_num_pages; WifiMarauderUart* uart; WifiMarauderUart* lp_uart; @@ -50,7 +70,8 @@ struct WifiMarauderApp { bool is_custom_tx_string; bool focus_console_start; bool show_stopscan_tip; - bool is_writing; + bool is_writing_pcap; + bool is_writing_log; // For input source and destination MAC in targeted deauth attack int special_case_input_step; @@ -83,4 +104,5 @@ typedef enum { WifiMarauderAppViewVarItemList, WifiMarauderAppViewConsoleOutput, WifiMarauderAppViewTextInput, + WifiMarauderAppViewWidget, } WifiMarauderAppView; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h b/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h index 990b457f5..79f96b107 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h @@ -5,5 +5,7 @@ typedef enum { WifiMarauderEventStartConsole, WifiMarauderEventStartKeyboard, WifiMarauderEventSaveSourceMac, - WifiMarauderEventSaveDestinationMac + WifiMarauderEventSaveDestinationMac, + WifiMarauderEventStartSettingsInit, + WifiMarauderEventStartLogViewer } WifiMarauderCustomEvent; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_pcap.c b/applications/external/wifi_marauder_companion/wifi_marauder_pcap.c index fc5f39022..73e3d98ea 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_pcap.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_pcap.c @@ -1,7 +1,7 @@ #include "wifi_marauder_app_i.h" #include "wifi_marauder_pcap.h" -void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) { +void wifi_marauder_get_prefix_from_sniff_cmd(char* dest, const char* command) { int start, end, delta; start = strlen("sniff"); end = strcspn(command, " "); @@ -10,10 +10,17 @@ void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) { dest[delta] = '\0'; } +void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) { + int end; + end = strcspn(command, " "); + strncpy(dest, command, end); + dest[end] = '\0'; +} + void wifi_marauder_create_pcap_file(WifiMarauderApp* app) { char prefix[10]; char capture_file_path[100]; - wifi_marauder_get_prefix_from_cmd(prefix, app->selected_tx_string); + wifi_marauder_get_prefix_from_sniff_cmd(prefix, app->selected_tx_string); int i = 0; do { @@ -21,7 +28,7 @@ void wifi_marauder_create_pcap_file(WifiMarauderApp* app) { capture_file_path, sizeof(capture_file_path), "%s/%s_%d.pcap", - MARAUDER_APP_FOLDER, + MARAUDER_APP_FOLDER_PCAPS, prefix, i); i++; @@ -30,4 +37,28 @@ void wifi_marauder_create_pcap_file(WifiMarauderApp* app) { if(!storage_file_open(app->capture_file, capture_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { dialog_message_show_storage_error(app->dialogs, "Cannot open pcap file"); } +} + +void wifi_marauder_create_log_file(WifiMarauderApp* app) { + char prefix[10]; + char log_file_path[100]; + wifi_marauder_get_prefix_from_cmd(prefix, app->selected_tx_string); + + int i = 0; + do { + snprintf( + log_file_path, + sizeof(log_file_path), + "%s/%s_%d.log", + MARAUDER_APP_FOLDER_LOGS, + prefix, + i); + i++; + } while(storage_file_exists(app->storage, log_file_path)); + + if(!storage_file_open(app->log_file, log_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + dialog_message_show_storage_error(app->dialogs, "Cannot open log file"); + } else { + strcpy(app->log_file_path, log_file_path); + } } \ No newline at end of file diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_pcap.h b/applications/external/wifi_marauder_companion/wifi_marauder_pcap.h index 29f8fcf8a..94f6282f3 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_pcap.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_pcap.h @@ -8,4 +8,13 @@ * * @param app Application context */ -void wifi_marauder_create_pcap_file(WifiMarauderApp* app); \ No newline at end of file +void wifi_marauder_create_pcap_file(WifiMarauderApp* app); + +/** + * Creates a log file to store text from console output. + * The file name will have a prefix according to the command being performed by the application (Eg: scanap_0.log) + * + * @param app Application context + */ +// same as wifi_marauder_create_pcap_file, but for log files (to save console text output) +void wifi_marauder_create_log_file(WifiMarauderApp* app); diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_uart.h b/applications/external/wifi_marauder_companion/wifi_marauder_uart.h index 4835d52ce..e352cfec5 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_uart.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_uart.h @@ -2,7 +2,7 @@ #include "furi_hal.h" -#define RX_BUF_SIZE (320) +#define RX_BUF_SIZE (2048) typedef struct WifiMarauderUart WifiMarauderUart; From 5340ebe9ab9a1ed2e30f3a3d57483022297c9be2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Mar 2023 04:51:30 +0300 Subject: [PATCH 16/16] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f94f117b8..817aab18b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * SubGHz: AN-Motors AT4 + Alutech AT4N - Add Manually support * SubGHz: Aprimatic keeloq emulation support + Add Manually * NFC: MF Classic User Dict -> Fix deleting of the key in extra actions menu +* Plugins: Update WiFi Marauder [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) * Plugins: Fix POCSAG pager `RIC:` text repetition and overlap (by @Willy-JL | PR #398) * OFW: NFC: MF Classic - Additional checks before invalidating the key (Fixes issues with not using MF keys from user dict) * OFW: Fix crash when emulating a DSGeneric key