mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-10 05:59:08 -07:00
Merge remote-tracking branch 'noproto/dev' into ulcdict
This commit is contained in:
@@ -7,7 +7,7 @@ App(
|
||||
icon="A_BadUsb_14",
|
||||
order=70,
|
||||
resources="resources",
|
||||
fap_libs=["assets"],
|
||||
fap_libs=["assets", "ble_profile"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="USB",
|
||||
)
|
||||
|
||||
@@ -35,6 +35,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t version = 0;
|
||||
uint32_t interface = 0;
|
||||
|
||||
if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
|
||||
do {
|
||||
@@ -44,6 +45,8 @@ static void bad_usb_load_settings(BadUsbApp* app) {
|
||||
break;
|
||||
|
||||
if(!flipper_format_read_string(fff, "layout", temp_str)) break;
|
||||
if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break;
|
||||
if(interface > BadUsbHidInterfaceBle) break;
|
||||
|
||||
state = true;
|
||||
} while(0);
|
||||
@@ -53,6 +56,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
|
||||
|
||||
if(state) {
|
||||
furi_string_set(app->keyboard_layout, temp_str);
|
||||
app->interface = interface;
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
FileInfo layout_file_info;
|
||||
@@ -64,6 +68,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
|
||||
}
|
||||
} else {
|
||||
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
|
||||
app->interface = BadUsbHidInterfaceUsb;
|
||||
}
|
||||
|
||||
furi_string_free(temp_str);
|
||||
@@ -79,6 +84,9 @@ static void bad_usb_save_settings(BadUsbApp* app) {
|
||||
fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION))
|
||||
break;
|
||||
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
|
||||
uint32_t interface_id = app->interface;
|
||||
if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1))
|
||||
break;
|
||||
} while(0);
|
||||
}
|
||||
|
||||
@@ -86,6 +94,11 @@ static void bad_usb_save_settings(BadUsbApp* app) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface) {
|
||||
app->interface = interface;
|
||||
bad_usb_view_set_interface(app->bad_usb_view, interface);
|
||||
}
|
||||
|
||||
BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
BadUsbApp* app = malloc(sizeof(BadUsbApp));
|
||||
|
||||
@@ -117,7 +130,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
// Custom Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));
|
||||
app->view_dispatcher, BadUsbAppViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, BadUsbAppViewPopup, popup_get_view(app->popup));
|
||||
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@@ -163,9 +180,13 @@ void bad_usb_app_free(BadUsbApp* app) {
|
||||
bad_usb_view_free(app->bad_usb_view);
|
||||
|
||||
// Custom Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
// Config menu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include "views/bad_usb_view.h"
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
@@ -33,6 +34,7 @@ struct BadUsbApp {
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
Popup* popup;
|
||||
VariableItemList* var_item_list;
|
||||
|
||||
BadUsbAppError error;
|
||||
@@ -41,11 +43,15 @@ struct BadUsbApp {
|
||||
BadUsb* bad_usb_view;
|
||||
BadUsbScript* bad_usb_script;
|
||||
|
||||
BadUsbHidInterface interface;
|
||||
FuriHalUsbInterface* usb_if_prev;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
BadUsbAppViewError,
|
||||
BadUsbAppViewWidget,
|
||||
BadUsbAppViewPopup,
|
||||
BadUsbAppViewWork,
|
||||
BadUsbAppViewConfig,
|
||||
} BadUsbAppView;
|
||||
|
||||
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "bad_usb_hid.h"
|
||||
#include <extra_profiles/hid_profile.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define TAG "BadUSB HID"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
||||
|
||||
void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) {
|
||||
furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg));
|
||||
return NULL;
|
||||
@@ -69,6 +72,155 @@ static const BadUsbHidApi hid_api_usb = {
|
||||
.release_all = hid_usb_release_all,
|
||||
.get_led_state = hid_usb_get_led_state,
|
||||
};
|
||||
const BadUsbHidApi* bad_usb_hid_get_interface() {
|
||||
return &hid_api_usb;
|
||||
|
||||
typedef struct {
|
||||
Bt* bt;
|
||||
FuriHalBleProfileBase* profile;
|
||||
HidStateCallback state_callback;
|
||||
void* callback_context;
|
||||
bool is_connected;
|
||||
} BleHidInstance;
|
||||
|
||||
static const BleProfileHidParams ble_hid_params = {
|
||||
.device_name_prefix = "BadUSB",
|
||||
.mac_xor = 0x0002,
|
||||
};
|
||||
|
||||
static void hid_ble_connection_status_callback(BtStatus status, void* context) {
|
||||
furi_assert(context);
|
||||
BleHidInstance* ble_hid = context;
|
||||
ble_hid->is_connected = (status == BtStatusConnected);
|
||||
if(ble_hid->state_callback) {
|
||||
ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) {
|
||||
UNUSED(hid_cfg);
|
||||
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
|
||||
ble_hid->bt = furi_record_open(RECORD_BT);
|
||||
bt_disconnect(ble_hid->bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
|
||||
bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
|
||||
|
||||
ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params);
|
||||
furi_check(ble_hid->profile);
|
||||
|
||||
furi_hal_bt_start_advertising();
|
||||
|
||||
bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid);
|
||||
|
||||
return ble_hid;
|
||||
}
|
||||
|
||||
void hid_ble_deinit(void* inst) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
|
||||
bt_set_status_changed_callback(ble_hid->bt, NULL, NULL);
|
||||
bt_disconnect(ble_hid->bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
bt_keys_storage_set_default_path(ble_hid->bt);
|
||||
|
||||
furi_check(bt_profile_restore_default(ble_hid->bt));
|
||||
furi_record_close(RECORD_BT);
|
||||
free(ble_hid);
|
||||
}
|
||||
|
||||
void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
ble_hid->state_callback = cb;
|
||||
ble_hid->callback_context = context;
|
||||
}
|
||||
|
||||
bool hid_ble_is_connected(void* inst) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
return ble_hid->is_connected;
|
||||
}
|
||||
|
||||
bool hid_ble_kb_press(void* inst, uint16_t button) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
return ble_profile_hid_kb_press(ble_hid->profile, button);
|
||||
}
|
||||
|
||||
bool hid_ble_kb_release(void* inst, uint16_t button) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
return ble_profile_hid_kb_release(ble_hid->profile, button);
|
||||
}
|
||||
|
||||
bool hid_ble_consumer_press(void* inst, uint16_t button) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
return ble_profile_hid_consumer_key_press(ble_hid->profile, button);
|
||||
}
|
||||
|
||||
bool hid_ble_consumer_release(void* inst, uint16_t button) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
return ble_profile_hid_consumer_key_release(ble_hid->profile, button);
|
||||
}
|
||||
|
||||
bool hid_ble_release_all(void* inst) {
|
||||
BleHidInstance* ble_hid = inst;
|
||||
furi_assert(ble_hid);
|
||||
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
|
||||
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
|
||||
return state;
|
||||
}
|
||||
|
||||
uint8_t hid_ble_get_led_state(void* inst) {
|
||||
UNUSED(inst);
|
||||
FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const BadUsbHidApi hid_api_ble = {
|
||||
.init = hid_ble_init,
|
||||
.deinit = hid_ble_deinit,
|
||||
.set_state_callback = hid_ble_set_state_callback,
|
||||
.is_connected = hid_ble_is_connected,
|
||||
|
||||
.kb_press = hid_ble_kb_press,
|
||||
.kb_release = hid_ble_kb_release,
|
||||
.consumer_press = hid_ble_consumer_press,
|
||||
.consumer_release = hid_ble_consumer_release,
|
||||
.release_all = hid_ble_release_all,
|
||||
.get_led_state = hid_ble_get_led_state,
|
||||
};
|
||||
|
||||
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) {
|
||||
if(interface == BadUsbHidInterfaceUsb) {
|
||||
return &hid_api_usb;
|
||||
} else {
|
||||
return &hid_api_ble;
|
||||
}
|
||||
}
|
||||
|
||||
void bad_usb_hid_ble_remove_pairing(void) {
|
||||
Bt* bt = furi_record_open(RECORD_BT);
|
||||
bt_disconnect(bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
|
||||
furi_hal_bt_stop_advertising();
|
||||
|
||||
bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
|
||||
bt_forget_bonded_devices(bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
bt_keys_storage_set_default_path(bt);
|
||||
|
||||
furi_check(bt_profile_restore_default(bt));
|
||||
furi_record_close(RECORD_BT);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ extern "C" {
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef enum {
|
||||
BadUsbHidInterfaceUsb,
|
||||
BadUsbHidInterfaceBle,
|
||||
} BadUsbHidInterface;
|
||||
|
||||
typedef struct {
|
||||
void* (*init)(FuriHalUsbHidConfig* hid_cfg);
|
||||
void (*deinit)(void* inst);
|
||||
@@ -21,7 +26,7 @@ typedef struct {
|
||||
uint8_t (*get_led_state)(void* inst);
|
||||
} BadUsbHidApi;
|
||||
|
||||
const BadUsbHidApi* bad_usb_hid_get_interface();
|
||||
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface);
|
||||
|
||||
void bad_usb_hid_ble_remove_pairing(void);
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
|
||||
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
|
||||
}
|
||||
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) {
|
||||
furi_assert(file_path);
|
||||
|
||||
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
|
||||
@@ -660,7 +660,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) {
|
||||
|
||||
bad_usb->st.state = BadUsbStateInit;
|
||||
bad_usb->st.error[0] = '\0';
|
||||
bad_usb->hid = bad_usb_hid_get_interface();
|
||||
bad_usb->hid = bad_usb_hid_get_interface(interface);
|
||||
|
||||
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
|
||||
furi_thread_start(bad_usb->thread);
|
||||
|
||||
@@ -34,7 +34,7 @@ typedef struct {
|
||||
|
||||
typedef struct BadUsbScript BadUsbScript;
|
||||
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path);
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface);
|
||||
|
||||
void bad_usb_script_close(BadUsbScript* bad_usb);
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
REM This is BadUSB demo script for ChromeOS by kowalski7cc
|
||||
REM This is BadUSB demo script for Chrome and ChromeOS by kowalski7cc
|
||||
|
||||
REM Exit from Overview
|
||||
ESC
|
||||
REM Open a new tab
|
||||
CTRL t
|
||||
REM wait for some slower chromebooks
|
||||
DELAY 1000
|
||||
REM Make sure we have omnibox focus
|
||||
CTRL l
|
||||
DELAY 200
|
||||
REM Open an empty editable page
|
||||
DEFAULT_DELAY 50
|
||||
STRING data:text/html, <html contenteditable autofocus><style>body{font-family:monospace;}
|
||||
STRING data:text/html, <html contenteditable autofocus><title>Flipper Zero BadUSB Demo</title><style>body{font-family:monospace;}
|
||||
ENTER
|
||||
DELAY 500
|
||||
|
||||
|
||||
@@ -5,14 +5,22 @@ REM Check the `lsusb` command to know your own devices IDs
|
||||
|
||||
REM This is BadUSB demo script for Linux/Gnome
|
||||
|
||||
REM Exit from Overview
|
||||
ESC
|
||||
DELAY 200
|
||||
REM Open terminal window
|
||||
DELAY 1000
|
||||
ALT F2
|
||||
DELAY 500
|
||||
STRING gnome-terminal --maximize
|
||||
DELAY 500
|
||||
DELAY 1000
|
||||
REM Let's guess user terminal, based on (almost) glib order with ptyxis now default in Fedora 41
|
||||
STRING sh -c "xdg-terminal-exec||kgx||ptyxis||gnome-terminal||mate-terminal||xfce4-terminal||tilix||konsole||xterm"
|
||||
DELAY 300
|
||||
ENTER
|
||||
REM It can take a bit to open the correct terminal
|
||||
DELAY 1500
|
||||
|
||||
REM Make sure we are running in a POSIX-compliant shell
|
||||
STRING env sh
|
||||
ENTER
|
||||
DELAY 750
|
||||
|
||||
REM Clear the screen in case some banner was displayed
|
||||
STRING clear
|
||||
|
||||
59
applications/main/bad_usb/scenes/bad_usb_scene_config.c
Normal file
59
applications/main/bad_usb/scenes/bad_usb_scene_config.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "../bad_usb_app_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
ConfigIndexKeyboardLayout,
|
||||
ConfigIndexBleUnpair,
|
||||
};
|
||||
|
||||
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
|
||||
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void draw_menu(BadUsbApp* bad_usb) {
|
||||
VariableItemList* var_item_list = bad_usb->var_item_list;
|
||||
|
||||
variable_item_list_reset(var_item_list);
|
||||
|
||||
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
|
||||
|
||||
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
|
||||
}
|
||||
|
||||
void bad_usb_scene_config_on_enter(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
VariableItemList* var_item_list = bad_usb->var_item_list;
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, bad_usb_scene_config_select_callback, bad_usb);
|
||||
draw_menu(bad_usb);
|
||||
variable_item_list_set_selected_item(var_item_list, 0);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == ConfigIndexKeyboardLayout) {
|
||||
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
|
||||
} else if(event.event == ConfigIndexBleUnpair) {
|
||||
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair);
|
||||
} else {
|
||||
furi_crash("Unknown key type");
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_usb_scene_config_on_exit(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
VariableItemList* var_item_list = bad_usb->var_item_list;
|
||||
|
||||
variable_item_list_reset(var_item_list);
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
ADD_SCENE(bad_usb, file_select, FileSelect)
|
||||
ADD_SCENE(bad_usb, work, Work)
|
||||
ADD_SCENE(bad_usb, error, Error)
|
||||
ADD_SCENE(bad_usb, config, Config)
|
||||
ADD_SCENE(bad_usb, config_layout, ConfigLayout)
|
||||
ADD_SCENE(bad_usb, confirm_unpair, ConfirmUnpair)
|
||||
ADD_SCENE(bad_usb, unpair_done, UnpairDone)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "../bad_usb_app_i.h"
|
||||
|
||||
void bad_usb_scene_confirm_unpair_widget_callback(
|
||||
GuiButtonType type,
|
||||
InputType input_type,
|
||||
void* context) {
|
||||
UNUSED(input_type);
|
||||
SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type};
|
||||
bad_usb_scene_confirm_unpair_on_event(context, event);
|
||||
}
|
||||
|
||||
void bad_usb_scene_confirm_unpair_on_enter(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Widget* widget = bad_usb->widget;
|
||||
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Cancel", bad_usb_scene_confirm_unpair_widget_callback, context);
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeRight,
|
||||
"Unpair",
|
||||
bad_usb_scene_confirm_unpair_widget_callback,
|
||||
context);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewWidget);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
SceneManager* scene_manager = bad_usb->scene_manager;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(scene_manager, BadUsbSceneUnpairDone);
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_previous_scene(scene_manager);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_usb_scene_confirm_unpair_on_exit(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Widget* widget = bad_usb->widget;
|
||||
|
||||
widget_reset(widget);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ void bad_usb_scene_error_on_enter(void* context) {
|
||||
"Disconnect from\nPC or phone to\nuse this function.");
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWidget);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
39
applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c
Normal file
39
applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "../bad_usb_app_i.h"
|
||||
|
||||
static void bad_usb_scene_unpair_done_popup_callback(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneConfig);
|
||||
}
|
||||
|
||||
void bad_usb_scene_unpair_done_on_enter(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Popup* popup = bad_usb->popup;
|
||||
|
||||
bad_usb_hid_ble_remove_pairing();
|
||||
|
||||
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
|
||||
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, bad_usb_scene_unpair_done_popup_callback);
|
||||
popup_set_context(popup, bad_usb);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewPopup);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
UNUSED(bad_usb);
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_usb_scene_unpair_done_on_exit(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Popup* popup = bad_usb->popup;
|
||||
UNUSED(popup);
|
||||
|
||||
popup_reset(popup);
|
||||
}
|
||||
@@ -20,14 +20,27 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
bad_usb_script_close(app->bad_usb_script);
|
||||
app->bad_usb_script = NULL;
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout);
|
||||
if(app->interface == BadUsbHidInterfaceBle) {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == InputKeyOk) {
|
||||
bad_usb_script_start_stop(app->bad_usb_script);
|
||||
consumed = true;
|
||||
} else if(event.event == InputKeyRight) {
|
||||
bad_usb_script_pause_resume(app->bad_usb_script);
|
||||
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
|
||||
bad_usb_set_interface(
|
||||
app,
|
||||
app->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb :
|
||||
BadUsbHidInterfaceBle);
|
||||
bad_usb_script_close(app->bad_usb_script);
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
|
||||
} else {
|
||||
bad_usb_script_pause_resume(app->bad_usb_script);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
@@ -39,7 +52,9 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
void bad_usb_scene_work_on_enter(void* context) {
|
||||
BadUsbApp* app = context;
|
||||
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path);
|
||||
bad_usb_view_set_interface(app->bad_usb_view, app->interface);
|
||||
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
|
||||
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
|
||||
|
||||
FuriString* file_name;
|
||||
|
||||
@@ -18,6 +18,7 @@ typedef struct {
|
||||
BadUsbState state;
|
||||
bool pause_wait;
|
||||
uint8_t anim_frame;
|
||||
BadUsbHidInterface interface;
|
||||
} BadUsbModel;
|
||||
|
||||
static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
@@ -40,14 +41,24 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
||||
furi_string_reset(disp_str);
|
||||
|
||||
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
|
||||
if(model->interface == BadUsbHidInterfaceBle) {
|
||||
canvas_draw_icon(canvas, 22, 24, &I_Bad_BLE_48x22);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
|
||||
}
|
||||
|
||||
BadUsbWorkerState state = model->state.state;
|
||||
|
||||
if((state == BadUsbStateIdle) || (state == BadUsbStateDone) ||
|
||||
(state == BadUsbStateNotConnected)) {
|
||||
elements_button_center(canvas, "Run");
|
||||
elements_button_left(canvas, "Layout");
|
||||
if(model->interface == BadUsbHidInterfaceBle) {
|
||||
elements_button_right(canvas, "USB");
|
||||
elements_button_left(canvas, "Config");
|
||||
} else {
|
||||
elements_button_right(canvas, "BLE");
|
||||
elements_button_left(canvas, "Layout");
|
||||
}
|
||||
} else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
if(!model->pause_wait) {
|
||||
@@ -266,6 +277,10 @@ void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
|
||||
true);
|
||||
}
|
||||
|
||||
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface) {
|
||||
with_view_model(bad_usb->view, BadUsbModel * model, { model->interface = interface; }, true);
|
||||
}
|
||||
|
||||
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
|
||||
bool is_idle = false;
|
||||
with_view_model(
|
||||
|
||||
@@ -23,4 +23,6 @@ void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
|
||||
|
||||
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
|
||||
|
||||
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface);
|
||||
|
||||
bool bad_usb_view_is_idle_state(BadUsb* bad_usb);
|
||||
|
||||
@@ -209,6 +209,15 @@ App(
|
||||
sources=["plugins/supported_cards/hworld.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="trt_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="trt_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/trt.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="nfc_start",
|
||||
targets=["f7"],
|
||||
|
||||
97
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
97
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
@@ -0,0 +1,97 @@
|
||||
// Flipper Zero parser for for Tianjin Railway Transit (TRT)
|
||||
// https://en.wikipedia.org/wiki/Tianjin_Metro
|
||||
// Reverse engineering and parser development by @Torron (Github: @zinongli)
|
||||
|
||||
#include "nfc_supported_card_plugin.h"
|
||||
#include <flipper_application.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||
#include <bit_lib.h>
|
||||
|
||||
#define TAG "TrtParser"
|
||||
#define LATEST_SALE_MARKER 0x02
|
||||
#define FULL_SALE_TIME_STAMP_PAGE 0x09
|
||||
#define BALANCE_PAGE 0x08
|
||||
#define SALE_RECORD_TIME_STAMP_A 0x0C
|
||||
#define SALE_RECORD_TIME_STAMP_B 0x0E
|
||||
#define SALE_YEAR_OFFSET 2000
|
||||
|
||||
static bool trt_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
furi_assert(device);
|
||||
furi_assert(parsed_data);
|
||||
|
||||
const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
do {
|
||||
uint8_t latest_sale_page = 0;
|
||||
|
||||
// Look for sale record signature
|
||||
if(data->page[SALE_RECORD_TIME_STAMP_A].data[0] == LATEST_SALE_MARKER) {
|
||||
latest_sale_page = SALE_RECORD_TIME_STAMP_A;
|
||||
} else if(data->page[SALE_RECORD_TIME_STAMP_B].data[0] == LATEST_SALE_MARKER) {
|
||||
latest_sale_page = SALE_RECORD_TIME_STAMP_B;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the sale record was backed up
|
||||
const uint8_t* partial_record_pointer = &data->page[latest_sale_page - 1].data[0];
|
||||
const uint8_t* full_record_pointer = &data->page[FULL_SALE_TIME_STAMP_PAGE].data[0];
|
||||
uint32_t latest_sale_record = bit_lib_get_bits_32(partial_record_pointer, 3, 20);
|
||||
uint32_t latest_sale_full_record = bit_lib_get_bits_32(full_record_pointer, 0, 27);
|
||||
if(latest_sale_record != (latest_sale_full_record & 0xFFFFF))
|
||||
break; // check if the copy matches
|
||||
if((latest_sale_record == 0) || (latest_sale_full_record == 0))
|
||||
break; // prevent false positive
|
||||
|
||||
// Parse date
|
||||
// yyy yyyymmmm dddddhhh hhnnnnnn
|
||||
uint16_t sale_year = ((latest_sale_full_record & 0x7F00000) >> 20) + SALE_YEAR_OFFSET;
|
||||
uint8_t sale_month = (latest_sale_full_record & 0xF0000) >> 16;
|
||||
uint8_t sale_day = (latest_sale_full_record & 0xF800) >> 11;
|
||||
uint8_t sale_hour = (latest_sale_full_record & 0x7C0) >> 6;
|
||||
uint8_t sale_minute = latest_sale_full_record & 0x3F;
|
||||
|
||||
// Parse balance
|
||||
uint16_t balance = bit_lib_get_bits_16(&data->page[BALANCE_PAGE].data[2], 0, 16);
|
||||
uint16_t balance_yuan = balance / 100;
|
||||
uint8_t balance_cent = balance % 100;
|
||||
|
||||
// Format string for rendering
|
||||
furi_string_cat_printf(parsed_data, "\e#TRT Tianjin Metro\n");
|
||||
furi_string_cat_printf(parsed_data, "Single-Use Ticket\n");
|
||||
furi_string_cat_printf(parsed_data, "Balance: %u.%02u RMB\n", balance_yuan, balance_cent);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Sale Date: \n%04u-%02d-%02d %02d:%02d",
|
||||
sale_year,
|
||||
sale_month,
|
||||
sale_day,
|
||||
sale_hour,
|
||||
sale_minute);
|
||||
parsed = true;
|
||||
} while(false);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* Actual implementation of app<>plugin interface */
|
||||
static const NfcSupportedCardsPlugin trt_plugin = {
|
||||
.protocol = NfcProtocolMfUltralight,
|
||||
.verify = NULL,
|
||||
.read = NULL,
|
||||
.parse = trt_parse,
|
||||
};
|
||||
|
||||
/* Plugin descriptor to comply with basic plugin specification */
|
||||
static const FlipperAppPluginDescriptor trt_plugin_descriptor = {
|
||||
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
|
||||
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
|
||||
.entry_point = &trt_plugin,
|
||||
};
|
||||
|
||||
/* Plugin entry point - must return a pointer to const descriptor */
|
||||
const FlipperAppPluginDescriptor* trt_plugin_ep(void) {
|
||||
return &trt_plugin_descriptor;
|
||||
}
|
||||
@@ -1351,3 +1351,8 @@ E69DD9015A43
|
||||
C8382A233993
|
||||
7B304F2A12A6
|
||||
FC9418BF788B
|
||||
|
||||
# H World Hotel Chain Room Keys
|
||||
543071543071
|
||||
5F01015F0101
|
||||
200510241234
|
||||
|
||||
@@ -45,6 +45,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
furi_string_set(m->header, "PRNG Analysis");
|
||||
break;
|
||||
case MfClassicNestedPhaseDictAttack:
|
||||
case MfClassicNestedPhaseDictAttackVerify:
|
||||
case MfClassicNestedPhaseDictAttackResume:
|
||||
furi_string_set(m->header, "Nested Dictionary");
|
||||
break;
|
||||
@@ -91,6 +92,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
float dict_progress = 0;
|
||||
if(m->nested_phase == MfClassicNestedPhaseAnalyzePRNG ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttack ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttackVerify ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttackResume) {
|
||||
// Phase: Nested dictionary attack
|
||||
uint8_t target_sector =
|
||||
|
||||
@@ -999,12 +999,13 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) {
|
||||
chat_event = subghz_chat_worker_get_event_chat(subghz_chat);
|
||||
switch(chat_event.event) {
|
||||
case SubGhzChatEventInputData:
|
||||
if(chat_event.c == CliKeyETX) {
|
||||
if(chat_event.c == CliSymbolAsciiETX) {
|
||||
printf("\r\n");
|
||||
chat_event.event = SubGhzChatEventUserExit;
|
||||
subghz_chat_worker_put_event_chat(subghz_chat, &chat_event);
|
||||
break;
|
||||
} else if((chat_event.c == CliKeyBackspace) || (chat_event.c == CliKeyDEL)) {
|
||||
} else if(
|
||||
(chat_event.c == CliSymbolAsciiBackspace) || (chat_event.c == CliSymbolAsciiDel)) {
|
||||
size_t len = furi_string_utf8_length(input);
|
||||
if(len > furi_string_utf8_length(name)) {
|
||||
printf("%s", "\e[D\e[1P");
|
||||
@@ -1026,7 +1027,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) {
|
||||
}
|
||||
furi_string_set(input, sysmsg);
|
||||
}
|
||||
} else if(chat_event.c == CliKeyCR) {
|
||||
} else if(chat_event.c == CliSymbolAsciiCR) {
|
||||
printf("\r\n");
|
||||
furi_string_push_back(input, '\r');
|
||||
furi_string_push_back(input, '\n');
|
||||
@@ -1040,7 +1041,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) {
|
||||
furi_string_printf(input, "%s", furi_string_get_cstr(name));
|
||||
printf("%s", furi_string_get_cstr(input));
|
||||
fflush(stdout);
|
||||
} else if(chat_event.c == CliKeyLF) {
|
||||
} else if(chat_event.c == CliSymbolAsciiLF) {
|
||||
//cut out the symbol \n
|
||||
} else {
|
||||
putc(chat_event.c, stdout);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cli/cli.h>
|
||||
#include <cli/cli_ansi.h>
|
||||
|
||||
void subghz_on_system_start(void);
|
||||
|
||||
Reference in New Issue
Block a user