diff --git a/applications/external/ble_spam/application.fam b/applications/external/ble_spam/application.fam index b6a3ce5ea..532a55cfb 100644 --- a/applications/external/ble_spam/application.fam +++ b/applications/external/ble_spam/application.fam @@ -8,7 +8,7 @@ App( fap_category="Bluetooth", fap_author="@Willy-JL @ECTO-1A @Spooks4576", fap_weburl="https://github.com/Flipper-XFW/Xtreme-Apps/tree/dev/ble_spam", - fap_version="3.2", + fap_version="3.3", fap_description="Flood BLE advertisements to cause spammy and annoying popups/notifications", fap_icon_assets="icons", fap_icon_assets_symbol="ble_spam", diff --git a/applications/external/ble_spam/ble_spam.c b/applications/external/ble_spam/ble_spam.c index 11eeaabac..5c7e886ec 100644 --- a/applications/external/ble_spam/ble_spam.c +++ b/applications/external/ble_spam/ble_spam.c @@ -142,6 +142,11 @@ static uint16_t delays[] = {20, 50, 100, 200}; typedef struct { Ctx ctx; + View* main_view; + bool lock_warning; + uint8_t lock_count; + FuriTimer* lock_timer; + bool resume; bool advertising; uint8_t delay; @@ -208,9 +213,9 @@ static void toggle_adv(State* state) { furi_thread_join(state->thread); if(state->resume) furi_hal_bt_start_advertising(); } else { + state->advertising = true; state->resume = furi_hal_bt_is_active(); furi_hal_bt_stop_advertising(); - state->advertising = true; furi_thread_start(state->thread); } } @@ -338,11 +343,15 @@ static void draw_callback(Canvas* canvas, void* _ctx) { "App+Spam: \e#WillyJL\e# XFW\n" "Apple+Crash: \e#ECTO-1A\e#\n" "Android+Win: \e#Spooks4576\e#\n" - " Version \e#3.2\e#", + " Version \e#3.3\e#", false); break; default: { if(!attack) break; + if(state->ctx.lock_keyboard && !state->advertising) { + // Forgive me Lord for I have sinned by handling state in draw + toggle_adv(state); + } char str[32]; canvas_set_font(canvas, FontBatteryPercent); @@ -378,6 +387,17 @@ static void draw_callback(Canvas* canvas, void* _ctx) { if(state->index < PAGE_MAX) { elements_button_right(canvas, next); } + + if(state->ctx.lock_keyboard) { + canvas_set_font(canvas, FontSecondary); + elements_bold_rounded_frame(canvas, 14, 8, 99, 48); + elements_multiline_text(canvas, 65, 26, "To unlock\npress:"); + canvas_draw_icon(canvas, 65, 42, &I_Pin_back_arrow_10x8); + canvas_draw_icon(canvas, 80, 42, &I_Pin_back_arrow_10x8); + canvas_draw_icon(canvas, 95, 42, &I_Pin_back_arrow_10x8); + canvas_draw_icon(canvas, 16, 13, &I_WarningDolphin_45x42); + canvas_draw_dot(canvas, 17, 61); + } } static bool input_callback(InputEvent* input, void* _ctx) { @@ -385,8 +405,22 @@ static bool input_callback(InputEvent* input, void* _ctx) { State* state = *(State**)view_get_model(view); bool consumed = false; - if(input->type == InputTypeShort || input->type == InputTypeLong || - input->type == InputTypeRepeat) { + if(state->ctx.lock_keyboard) { + consumed = true; + with_view_model( + state->main_view, State * *model, { (*model)->lock_warning = true; }, true); + if(state->lock_count == 0) { + furi_timer_start(state->lock_timer, pdMS_TO_TICKS(1000)); + } + if(input->type == InputTypeShort && input->key == InputKeyBack) { + state->lock_count++; + } + if(state->lock_count >= 3) { + furi_timer_start(state->lock_timer, 1); + } + } else if( + input->type == InputTypeShort || input->type == InputTypeLong || + input->type == InputTypeRepeat) { consumed = true; bool is_attack = state->index >= 0 && state->index <= ATTACKS_COUNT - 1; @@ -442,6 +476,18 @@ static bool input_callback(InputEvent* input, void* _ctx) { return consumed; } +static void lock_timer_callback(void* _ctx) { + State* state = _ctx; + if(state->lock_count < 3) { + notification_message_block(state->ctx.notification, &sequence_display_backlight_off); + } else { + state->ctx.lock_keyboard = false; + } + with_view_model( + state->main_view, State * *model, { (*model)->lock_warning = false; }, true); + state->lock_count = 0; +} + static bool back_event_callback(void* _ctx) { Ctx* ctx = _ctx; return scene_manager_handle_back_event(ctx->scene_manager); @@ -455,6 +501,7 @@ int32_t ble_spam(void* p) { furi_thread_set_context(state->thread, state); furi_thread_set_stack_size(state->thread, 4096); state->ctx.led_indicator = true; + state->lock_timer = furi_timer_alloc(lock_timer_callback, FuriTimerTypeOnce, state); state->ctx.notification = furi_record_open(RECORD_NOTIFICATION); Gui* gui = furi_record_open(RECORD_GUI); @@ -464,14 +511,14 @@ int32_t ble_spam(void* p) { view_dispatcher_set_navigation_event_callback(state->ctx.view_dispatcher, back_event_callback); state->ctx.scene_manager = scene_manager_alloc(&scene_handlers, &state->ctx); - View* view_main = view_alloc(); - view_allocate_model(view_main, ViewModelTypeLockFree, sizeof(State*)); + state->main_view = view_alloc(); + view_allocate_model(state->main_view, ViewModelTypeLocking, sizeof(State*)); with_view_model( - view_main, State * *model, { *model = state; }, false); - view_set_context(view_main, view_main); - view_set_draw_callback(view_main, draw_callback); - view_set_input_callback(view_main, input_callback); - view_dispatcher_add_view(state->ctx.view_dispatcher, ViewMain, view_main); + state->main_view, State * *model, { *model = state; }, false); + view_set_context(state->main_view, state->main_view); + view_set_draw_callback(state->main_view, draw_callback); + view_set_input_callback(state->main_view, input_callback); + view_dispatcher_add_view(state->ctx.view_dispatcher, ViewMain, state->main_view); state->ctx.byte_input = byte_input_alloc(); view_dispatcher_add_view( @@ -508,13 +555,14 @@ int32_t ble_spam(void* p) { variable_item_list_free(state->ctx.variable_item_list); view_dispatcher_remove_view(state->ctx.view_dispatcher, ViewMain); - view_free(view_main); + view_free(state->main_view); scene_manager_free(state->ctx.scene_manager); view_dispatcher_free(state->ctx.view_dispatcher); furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); + furi_timer_free(state->lock_timer); furi_thread_free(state->thread); free(state); return 0; diff --git a/applications/external/ble_spam/ble_spam.h b/applications/external/ble_spam/ble_spam.h index b72ca7cc5..6be71147e 100644 --- a/applications/external/ble_spam/ble_spam.h +++ b/applications/external/ble_spam/ble_spam.h @@ -21,6 +21,7 @@ enum { ConfigRandomMac, ConfigExtraStart = ConfigRandomMac, ConfigLedIndicator, + ConfigLockKeyboard, }; typedef struct Attack Attack; @@ -30,6 +31,7 @@ typedef struct { uint8_t byte_store[3]; VariableItemListEnterCallback fallback_config_enter; bool led_indicator; + bool lock_keyboard; NotificationApp* notification; ViewDispatcher* view_dispatcher; diff --git a/applications/external/ble_spam/scenes/config.c b/applications/external/ble_spam/scenes/config.c index 376d336ac..cfbbbf952 100644 --- a/applications/external/ble_spam/scenes/config.c +++ b/applications/external/ble_spam/scenes/config.c @@ -16,7 +16,9 @@ static void config_bool(VariableItemList* list, const char* name, bool* value) { static void config_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; scene_manager_set_scene_state(ctx->scene_manager, SceneConfig, index); - if(ctx->attack->protocol && ctx->attack->protocol->config_count) { + if(!ctx->attack->protocol) { + index--; + } else if(ctx->attack->protocol->config_count) { uint8_t extra = ctx->attack->protocol->config_count(&ctx->attack->payload.cfg); if(index > extra) index -= extra; } @@ -26,6 +28,11 @@ static void config_callback(void* _ctx, uint32_t index) { break; case ConfigLedIndicator: break; + case ConfigLockKeyboard: + ctx->lock_keyboard = true; + scene_manager_previous_scene(ctx->scene_manager); + notification_message_block(ctx->notification, &sequence_display_backlight_off); + break; default: break; } @@ -49,6 +56,8 @@ void scene_config_on_enter(void* _ctx) { config_bool(list, "LED Indicator", &ctx->led_indicator); + variable_item_list_add(list, "Lock Keyboard", 0, NULL, NULL); + variable_item_list_set_selected_item( list, scene_manager_get_scene_state(ctx->scene_manager, SceneConfig));