diff --git a/applications/external/evil_portal/application.fam b/applications/external/evil_portal/application.fam new file mode 100644 index 000000000..b9936fe04 --- /dev/null +++ b/applications/external/evil_portal/application.fam @@ -0,0 +1,12 @@ +App( + appid="evil_portal", + name="[ESP32] Evil Portal", + apptype=FlipperAppType.EXTERNAL, + entry_point="evil_portal_app", + cdefines=["APP_EVIL_PORTAL"], + requires=["gui"], + stack_size=1 * 1024, + order=90, + fap_icon="icons/evil_portal_10px.png", + fap_category="GPIO", +) diff --git a/applications/external/evil_portal/evil_portal_app.c b/applications/external/evil_portal/evil_portal_app.c new file mode 100644 index 000000000..cce26c9ba --- /dev/null +++ b/applications/external/evil_portal/evil_portal_app.c @@ -0,0 +1,119 @@ +#include "evil_portal_app_i.h" +#include "helpers/evil_portal_storage.h" + +#include +#include + +static bool evil_portal_app_custom_event_callback(void *context, + uint32_t event) { + furi_assert(context); + Evil_PortalApp *app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool evil_portal_app_back_event_callback(void *context) { + furi_assert(context); + Evil_PortalApp *app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void evil_portal_app_tick_event_callback(void *context) { + furi_assert(context); + Evil_PortalApp *app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +Evil_PortalApp *evil_portal_app_alloc() { + Evil_PortalApp *app = malloc(sizeof(Evil_PortalApp)); + + app->sent_html = false; + app->sent_ap = false; + app->sent_reset = false; + app->has_command_queue = false; + app->command_index = 0; + app->portal_logs = furi_string_alloc(); + + app->gui = furi_record_open(RECORD_GUI); + + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&evil_portal_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, evil_portal_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, evil_portal_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, evil_portal_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, + ViewDispatcherTypeFullscreen); + + app->var_item_list = variable_item_list_alloc(); + view_dispatcher_add_view(app->view_dispatcher, Evil_PortalAppViewVarItemList, + variable_item_list_get_view(app->var_item_list)); + + for (int i = 0; i < NUM_MENU_ITEMS; ++i) { + app->selected_option_index[i] = 0; + } + + app->text_box = text_box_alloc(); + view_dispatcher_add_view(app->view_dispatcher, + Evil_PortalAppViewConsoleOutput, + text_box_get_view(app->text_box)); + app->text_box_store = furi_string_alloc(); + furi_string_reserve(app->text_box_store, EVIL_PORTAL_TEXT_BOX_STORE_SIZE); + + scene_manager_next_scene(app->scene_manager, Evil_PortalSceneStart); + + return app; +} + +void evil_portal_app_free(Evil_PortalApp *app) { + + // save latest logs + if (furi_string_utf8_length(app->portal_logs) > 0) { + write_logs(app->portal_logs); + furi_string_free(app->portal_logs); + } + + // Send reset event to dev board + evil_portal_uart_tx((uint8_t *)(RESET_CMD), strlen(RESET_CMD)); + evil_portal_uart_tx((uint8_t *)("\n"), 1); + + furi_assert(app); + + // Views + view_dispatcher_remove_view(app->view_dispatcher, + Evil_PortalAppViewVarItemList); + view_dispatcher_remove_view(app->view_dispatcher, + Evil_PortalAppViewConsoleOutput); + + text_box_free(app->text_box); + furi_string_free(app->text_box_store); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + evil_portal_uart_free(app->uart); + + // Close records + furi_record_close(RECORD_GUI); + + free(app); +} + +int32_t evil_portal_app(void *p) { + UNUSED(p); + Evil_PortalApp *evil_portal_app = evil_portal_app_alloc(); + + evil_portal_app->uart = evil_portal_uart_init(evil_portal_app); + + view_dispatcher_run(evil_portal_app->view_dispatcher); + + evil_portal_app_free(evil_portal_app); + + return 0; +} diff --git a/applications/external/evil_portal/evil_portal_app.h b/applications/external/evil_portal/evil_portal_app.h new file mode 100644 index 000000000..65c047ea5 --- /dev/null +++ b/applications/external/evil_portal/evil_portal_app.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Evil_PortalApp Evil_PortalApp; + +#ifdef __cplusplus +} +#endif diff --git a/applications/external/evil_portal/evil_portal_app_i.h b/applications/external/evil_portal/evil_portal_app_i.h new file mode 100644 index 000000000..a5b67b072 --- /dev/null +++ b/applications/external/evil_portal/evil_portal_app_i.h @@ -0,0 +1,60 @@ +#pragma once + +#include "evil_portal_app.h" +#include "evil_portal_custom_event.h" +#include "evil_portal_uart.h" +#include "scenes/evil_portal_scene.h" + +#include +#include +#include +#include +#include + +#define NUM_MENU_ITEMS (4) + +#define EVIL_PORTAL_TEXT_BOX_STORE_SIZE (4096) +#define UART_CH (FuriHalUartIdUSART1) + +#define SET_HTML_CMD "sethtml" +#define SET_AP_CMD "setap" +#define RESET_CMD "reset" + +struct Evil_PortalApp { + Gui *gui; + ViewDispatcher *view_dispatcher; + SceneManager *scene_manager; + + FuriString* portal_logs; + const char *command_queue[1]; + int command_index; + bool has_command_queue; + + FuriString *text_box_store; + size_t text_box_store_strlen; + TextBox *text_box; + + VariableItemList *var_item_list; + Evil_PortalUart *uart; + + int selected_menu_index; + int selected_option_index[NUM_MENU_ITEMS]; + const char *selected_tx_string; + bool is_command; + bool is_custom_tx_string; + bool focus_console_start; + bool show_stopscan_tip; + bool sent_ap; + bool sent_html; + bool sent_reset; + int BAUDRATE; + + uint8_t *index_html; + uint8_t *ap_name; +}; + +typedef enum { + Evil_PortalAppViewVarItemList, + Evil_PortalAppViewConsoleOutput, + Evil_PortalAppViewStartPortal, +} Evil_PortalAppView; diff --git a/applications/external/evil_portal/evil_portal_custom_event.h b/applications/external/evil_portal/evil_portal_custom_event.h new file mode 100644 index 000000000..dfcdadfa9 --- /dev/null +++ b/applications/external/evil_portal/evil_portal_custom_event.h @@ -0,0 +1,8 @@ +#pragma once + +typedef enum { + Evil_PortalEventRefreshConsoleOutput = 0, + Evil_PortalEventStartConsole, + Evil_PortalEventStartKeyboard, + Evil_PortalEventStartPortal, +} Evil_PortalCustomEvent; diff --git a/applications/external/evil_portal/evil_portal_uart.c b/applications/external/evil_portal/evil_portal_uart.c new file mode 100644 index 000000000..57848cabc --- /dev/null +++ b/applications/external/evil_portal/evil_portal_uart.c @@ -0,0 +1,147 @@ +#include "evil_portal_app_i.h" +#include "evil_portal_uart.h" +#include "helpers/evil_portal_storage.h" + +struct Evil_PortalUart { + Evil_PortalApp *app; + FuriThread *rx_thread; + FuriStreamBuffer *rx_stream; + uint8_t rx_buf[RX_BUF_SIZE + 1]; + void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void *context); +}; + +typedef enum { + WorkerEvtStop = (1 << 0), + WorkerEvtRxDone = (1 << 1), +} WorkerEvtFlags; + +void evil_portal_uart_set_handle_rx_data_cb( + Evil_PortalUart *uart, + void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void *context)) { + furi_assert(uart); + uart->handle_rx_data_cb = handle_rx_data_cb; +} + +#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone) + +void evil_portal_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void *context) { + Evil_PortalUart *uart = (Evil_PortalUart *)context; + + if (ev == UartIrqEventRXNE) { + furi_stream_buffer_send(uart->rx_stream, &data, 1, 0); + furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtRxDone); + } +} + +static int32_t uart_worker(void *context) { + Evil_PortalUart *uart = (void *)context; + + while (1) { + + uint32_t events = furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, + FuriFlagWaitAny, FuriWaitForever); + furi_check((events & FuriFlagError) == 0); + if (events & WorkerEvtStop) + break; + if (events & WorkerEvtRxDone) { + size_t len = furi_stream_buffer_receive(uart->rx_stream, uart->rx_buf, + RX_BUF_SIZE, 0); + + if (len > 0) { + if (uart->handle_rx_data_cb) { + uart->handle_rx_data_cb(uart->rx_buf, len, uart->app); + + if (uart->app->has_command_queue) { + if (uart->app->command_index < 1) { + if (0 == + strncmp(SET_AP_CMD, + uart->app->command_queue[uart->app->command_index], + strlen(SET_AP_CMD))) { + FuriString *out_data = furi_string_alloc(); + + furi_string_cat(out_data, "setap="); + furi_string_cat(out_data, (char *)uart->app->ap_name); + + evil_portal_uart_tx((uint8_t *)(furi_string_get_cstr(out_data)), + strlen(furi_string_get_cstr(out_data))); + evil_portal_uart_tx((uint8_t *)("\n"), 1); + + uart->app->sent_ap = true; + + free(out_data); + free(uart->app->ap_name); + } + + uart->app->command_index = 0; + uart->app->has_command_queue = false; + uart->app->command_queue[0] = ""; + } + } + + if (uart->app->sent_reset == false) { + furi_string_cat(uart->app->portal_logs, (char *)uart->rx_buf); + } + + if (furi_string_utf8_length(uart->app->portal_logs) > 4000) { + write_logs(uart->app->portal_logs); + furi_string_reset(uart->app->portal_logs); + } + } else { + uart->rx_buf[len] = '\0'; + if (uart->app->sent_reset == false) { + furi_string_cat(uart->app->portal_logs, (char *)uart->rx_buf); + } + + if (furi_string_utf8_length(uart->app->portal_logs) > 4000) { + write_logs(uart->app->portal_logs); + furi_string_reset(uart->app->portal_logs); + } + } + } + } + } + + furi_stream_buffer_free(uart->rx_stream); + + return 0; +} + +void evil_portal_uart_tx(uint8_t *data, size_t len) { + furi_hal_uart_tx(UART_CH, data, len); +} + +Evil_PortalUart *evil_portal_uart_init(Evil_PortalApp *app) { + Evil_PortalUart *uart = malloc(sizeof(Evil_PortalUart)); + uart->app = app; + // Init all rx stream and thread early to avoid crashes + uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1); + uart->rx_thread = furi_thread_alloc(); + furi_thread_set_name(uart->rx_thread, "Evil_PortalUartRxThread"); + furi_thread_set_stack_size(uart->rx_thread, 1024); + furi_thread_set_context(uart->rx_thread, uart); + furi_thread_set_callback(uart->rx_thread, uart_worker); + + furi_thread_start(uart->rx_thread); + + furi_hal_console_disable(); + if (app->BAUDRATE == 0) { + app->BAUDRATE = 115200; + } + furi_hal_uart_set_br(UART_CH, app->BAUDRATE); + furi_hal_uart_set_irq_cb(UART_CH, evil_portal_uart_on_irq_cb, uart); + + return uart; +} + +void evil_portal_uart_free(Evil_PortalUart *uart) { + furi_assert(uart); + + furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtStop); + furi_thread_join(uart->rx_thread); + furi_thread_free(uart->rx_thread); + + furi_hal_uart_set_irq_cb(UART_CH, NULL, NULL); + furi_hal_console_enable(); + + free(uart); +} diff --git a/applications/external/evil_portal/evil_portal_uart.h b/applications/external/evil_portal/evil_portal_uart.h new file mode 100644 index 000000000..97e1a46fa --- /dev/null +++ b/applications/external/evil_portal/evil_portal_uart.h @@ -0,0 +1,14 @@ +#pragma once + +#include "furi_hal.h" + +#define RX_BUF_SIZE (320) + +typedef struct Evil_PortalUart Evil_PortalUart; + +void evil_portal_uart_set_handle_rx_data_cb( + Evil_PortalUart *uart, + void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void *context)); +void evil_portal_uart_tx(uint8_t *data, size_t len); +Evil_PortalUart *evil_portal_uart_init(Evil_PortalApp *app); +void evil_portal_uart_free(Evil_PortalUart *uart); diff --git a/applications/external/evil_portal/helpers/evil_portal_storage.c b/applications/external/evil_portal/helpers/evil_portal_storage.c new file mode 100644 index 000000000..e31c8c8de --- /dev/null +++ b/applications/external/evil_portal/helpers/evil_portal_storage.c @@ -0,0 +1,118 @@ +#include "evil_portal_storage.h" + +static Storage *evil_portal_open_storage() { + return furi_record_open(RECORD_STORAGE); +} + +static void evil_portal_close_storage() { furi_record_close(RECORD_STORAGE); } + +void evil_portal_read_index_html(void *context) { + + Evil_PortalApp *app = context; + Storage *storage = evil_portal_open_storage(); + FileInfo fi; + + if (storage_common_stat(storage, EVIL_PORTAL_INDEX_SAVE_PATH, &fi) == + FSE_OK) { + File *index_html = storage_file_alloc(storage); + if (storage_file_open(index_html, EVIL_PORTAL_INDEX_SAVE_PATH, FSAM_READ, + FSOM_OPEN_EXISTING)) { + app->index_html = malloc((size_t)fi.size); + uint8_t *buf_ptr = app->index_html; + size_t read = 0; + while (read < fi.size) { + size_t to_read = fi.size - read; + if (to_read > UINT16_MAX) + to_read = UINT16_MAX; + uint16_t now_read = + storage_file_read(index_html, buf_ptr, (uint16_t)to_read); + read += now_read; + buf_ptr += now_read; + } + free(buf_ptr); + } + storage_file_close(index_html); + storage_file_free(index_html); + } else { + char *html_error = + "Evil portal
Unable to read the html file.
" + "Is the SD Card set up correctly?
See instructions @ " + "github.com/bigbrodude6119/flipper-zero-evil-portal
" + "Under the 'Install pre-built app on the flipper' section."; + app->index_html = (uint8_t *)html_error; + } + + evil_portal_close_storage(); +} + +void evil_portal_read_ap_name(void *context) { + Evil_PortalApp *app = context; + Storage *storage = evil_portal_open_storage(); + FileInfo fi; + + if (storage_common_stat(storage, EVIL_PORTAL_AP_SAVE_PATH, &fi) == FSE_OK) { + File *ap_name = storage_file_alloc(storage); + if (storage_file_open(ap_name, EVIL_PORTAL_AP_SAVE_PATH, FSAM_READ, + FSOM_OPEN_EXISTING)) { + app->ap_name = malloc((size_t)fi.size); + uint8_t *buf_ptr = app->ap_name; + size_t read = 0; + while (read < fi.size) { + size_t to_read = fi.size - read; + if (to_read > UINT16_MAX) + to_read = UINT16_MAX; + uint16_t now_read = + storage_file_read(ap_name, buf_ptr, (uint16_t)to_read); + read += now_read; + buf_ptr += now_read; + } + free(buf_ptr); + } + storage_file_close(ap_name); + storage_file_free(ap_name); + } else { + char *app_default = "Evil Portal"; + app->ap_name = (uint8_t *)app_default; + } + evil_portal_close_storage(); +} + +char *sequential_file_resolve_path(Storage *storage, const char *dir, + const char *prefix, const char *extension) { + if (storage == NULL || dir == NULL || prefix == NULL || extension == NULL) { + return NULL; + } + + char file_path[256]; + int file_index = 0; + + do { + if (snprintf(file_path, sizeof(file_path), "%s/%s_%d.%s", dir, prefix, + file_index, extension) < 0) { + return NULL; + } + file_index++; + } while (storage_file_exists(storage, file_path)); + + return strdup(file_path); +} + +void write_logs(FuriString *portal_logs) { + Storage *storage = evil_portal_open_storage(); + + if (!storage_file_exists(storage, EVIL_PORTAL_LOG_SAVE_PATH)) { + storage_simply_mkdir(storage, EVIL_PORTAL_LOG_SAVE_PATH); + } + + char *seq_file_path = sequential_file_resolve_path( + storage, EVIL_PORTAL_LOG_SAVE_PATH, "log", "txt"); + + File *file = storage_file_alloc(storage); + + if (storage_file_open(file, seq_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + storage_file_write(file, furi_string_get_cstr(portal_logs), furi_string_utf8_length(portal_logs)); + } + storage_file_close(file); + storage_file_free(file); + evil_portal_close_storage(); +} \ No newline at end of file diff --git a/applications/external/evil_portal/helpers/evil_portal_storage.h b/applications/external/evil_portal/helpers/evil_portal_storage.h new file mode 100644 index 000000000..74ace6acc --- /dev/null +++ b/applications/external/evil_portal/helpers/evil_portal_storage.h @@ -0,0 +1,17 @@ +#include "../evil_portal_app_i.h" +#include +#include +#include +#include +#include + +#define PORTAL_FILE_DIRECTORY_PATH EXT_PATH("apps_data/evil_portal") +#define EVIL_PORTAL_INDEX_SAVE_PATH PORTAL_FILE_DIRECTORY_PATH "/index.html" +#define EVIL_PORTAL_AP_SAVE_PATH PORTAL_FILE_DIRECTORY_PATH "/ap.config.txt" +#define EVIL_PORTAL_LOG_SAVE_PATH PORTAL_FILE_DIRECTORY_PATH "/logs" + +void evil_portal_read_index_html(void *context); +void evil_portal_read_ap_name(void *context); +void write_logs(FuriString* portal_logs); +char *sequential_file_resolve_path(Storage *storage, const char *dir, + const char *prefix, const char *extension); diff --git a/applications/external/evil_portal/icons/evil_portal_10px.png b/applications/external/evil_portal/icons/evil_portal_10px.png new file mode 100644 index 000000000..c13534660 Binary files /dev/null and b/applications/external/evil_portal/icons/evil_portal_10px.png differ diff --git a/applications/external/evil_portal/scenes/evil_portal_scene.c b/applications/external/evil_portal/scenes/evil_portal_scene.c new file mode 100644 index 000000000..4573642e4 --- /dev/null +++ b/applications/external/evil_portal/scenes/evil_portal_scene.c @@ -0,0 +1,31 @@ +#include "evil_portal_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const evil_portal_scene_on_enter_handlers[])(void *) = { +#include "evil_portal_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const evil_portal_scene_on_event_handlers[])(void *context, + SceneManagerEvent event) = { +#include "evil_portal_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const evil_portal_scene_on_exit_handlers[])(void *context) = { +#include "evil_portal_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers evil_portal_scene_handlers = { + .on_enter_handlers = evil_portal_scene_on_enter_handlers, + .on_event_handlers = evil_portal_scene_on_event_handlers, + .on_exit_handlers = evil_portal_scene_on_exit_handlers, + .scene_num = Evil_PortalSceneNum, +}; diff --git a/applications/external/evil_portal/scenes/evil_portal_scene.h b/applications/external/evil_portal/scenes/evil_portal_scene.h new file mode 100644 index 000000000..59a8c711e --- /dev/null +++ b/applications/external/evil_portal/scenes/evil_portal_scene.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) Evil_PortalScene##id, +typedef enum { +#include "evil_portal_scene_config.h" + Evil_PortalSceneNum, +} Evil_PortalScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers evil_portal_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) \ + void prefix##_scene_##name##_on_enter(void *); +#include "evil_portal_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void *context, SceneManagerEvent event); +#include "evil_portal_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) \ + void prefix##_scene_##name##_on_exit(void *context); +#include "evil_portal_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/evil_portal/scenes/evil_portal_scene_config.h b/applications/external/evil_portal/scenes/evil_portal_scene_config.h new file mode 100644 index 000000000..94b09ae46 --- /dev/null +++ b/applications/external/evil_portal/scenes/evil_portal_scene_config.h @@ -0,0 +1,2 @@ +ADD_SCENE(evil_portal, start, Start) +ADD_SCENE(evil_portal, console_output, ConsoleOutput) diff --git a/applications/external/evil_portal/scenes/evil_portal_scene_console_output.c b/applications/external/evil_portal/scenes/evil_portal_scene_console_output.c new file mode 100644 index 000000000..b81da3116 --- /dev/null +++ b/applications/external/evil_portal/scenes/evil_portal_scene_console_output.c @@ -0,0 +1,157 @@ +#include "../evil_portal_app_i.h" +#include "../helpers/evil_portal_storage.h" + +void evil_portal_console_output_handle_rx_data_cb(uint8_t *buf, size_t len, + void *context) { + furi_assert(context); + Evil_PortalApp *app = context; + + // If text box store gets too big, then truncate it + app->text_box_store_strlen += len; + if (app->text_box_store_strlen >= EVIL_PORTAL_TEXT_BOX_STORE_SIZE - 1) { + furi_string_right(app->text_box_store, app->text_box_store_strlen / 2); + app->text_box_store_strlen = furi_string_size(app->text_box_store) + len; + } + + // Null-terminate buf and append to text box store + buf[len] = '\0'; + furi_string_cat_printf(app->text_box_store, "%s", buf); + + view_dispatcher_send_custom_event(app->view_dispatcher, + Evil_PortalEventRefreshConsoleOutput); +} + +void evil_portal_scene_console_output_on_enter(void *context) { + Evil_PortalApp *app = context; + + TextBox *text_box = app->text_box; + text_box_reset(app->text_box); + text_box_set_font(text_box, TextBoxFontText); + if (app->focus_console_start) { + text_box_set_focus(text_box, TextBoxFocusStart); + } else { + text_box_set_focus(text_box, TextBoxFocusEnd); + } + + if (app->is_command) { + furi_string_reset(app->text_box_store); + app->text_box_store_strlen = 0; + app->sent_reset = false; + + if (0 == strncmp("help", app->selected_tx_string, strlen("help"))) { + const char *help_msg = + "BLUE = Waiting\nGREEN = Good\nRED = Bad\n\nThis project is a " + "WIP.\ngithub.com/bigbrodude6119/flipper-zero-evil-portal\n\n" + "Version 0.0.2\n\n"; + furi_string_cat_str(app->text_box_store, help_msg); + app->text_box_store_strlen += strlen(help_msg); + if (app->show_stopscan_tip) { + const char *msg = "Press BACK to return\n"; + furi_string_cat_str(app->text_box_store, msg); + app->text_box_store_strlen += strlen(msg); + } + } + + if (0 == strncmp("savelogs", app->selected_tx_string, strlen("savelogs"))) { + const char *help_msg = "Logs saved.\n\n"; + furi_string_cat_str(app->text_box_store, help_msg); + app->text_box_store_strlen += strlen(help_msg); + write_logs(app->portal_logs); + furi_string_reset(app->portal_logs); + if (app->show_stopscan_tip) { + const char *msg = "Press BACK to return\n"; + furi_string_cat_str(app->text_box_store, msg); + app->text_box_store_strlen += strlen(msg); + } + } + + if (0 == + strncmp(SET_HTML_CMD, app->selected_tx_string, strlen(SET_HTML_CMD))) { + app->command_queue[0] = SET_AP_CMD; + app->has_command_queue = true; + app->command_index = 0; + if (app->show_stopscan_tip) { + const char *msg = + "Starting portal\nIf no response press\nBACK to return\n"; + furi_string_cat_str(app->text_box_store, msg); + app->text_box_store_strlen += strlen(msg); + } + } + + if (0 == strncmp(RESET_CMD, app->selected_tx_string, strlen(RESET_CMD))) { + app->sent_reset = true; + if (app->show_stopscan_tip) { + const char *msg = "Reseting portal\nPress BACK to return\n\n\n\n"; + furi_string_cat_str(app->text_box_store, msg); + app->text_box_store_strlen += strlen(msg); + } + } + } + + text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store)); + + scene_manager_set_scene_state(app->scene_manager, + Evil_PortalSceneConsoleOutput, 0); + view_dispatcher_switch_to_view(app->view_dispatcher, + Evil_PortalAppViewConsoleOutput); + + // Register callback to receive data + evil_portal_uart_set_handle_rx_data_cb( + app->uart, evil_portal_console_output_handle_rx_data_cb); + + if (app->is_command && app->selected_tx_string) { + if (0 == + strncmp(SET_HTML_CMD, app->selected_tx_string, strlen(SET_HTML_CMD))) { + evil_portal_read_index_html(context); + + FuriString *data = furi_string_alloc(); + furi_string_cat(data, "sethtml="); + furi_string_cat(data, (char *)app->index_html); + + evil_portal_uart_tx((uint8_t *)(furi_string_get_cstr(data)), + strlen(furi_string_get_cstr(data))); + evil_portal_uart_tx((uint8_t *)("\n"), 1); + + app->sent_html = true; + + free(data); + free(app->index_html); + + evil_portal_read_ap_name(context); + } else if (0 == + strncmp(RESET_CMD, app->selected_tx_string, strlen(RESET_CMD))) { + app->sent_html = false; + app->sent_ap = false; + evil_portal_uart_tx((uint8_t *)(app->selected_tx_string), + strlen(app->selected_tx_string)); + evil_portal_uart_tx((uint8_t *)("\n"), 1); + } else if (1 == strncmp("help", app->selected_tx_string, strlen("help"))) { + evil_portal_uart_tx((uint8_t *)(app->selected_tx_string), + strlen(app->selected_tx_string)); + evil_portal_uart_tx((uint8_t *)("\n"), 1); + } + } +} + +bool evil_portal_scene_console_output_on_event(void *context, + SceneManagerEvent event) { + Evil_PortalApp *app = context; + + bool consumed = false; + + if (event.type == SceneManagerEventTypeCustom) { + text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store)); + consumed = true; + } else if (event.type == SceneManagerEventTypeTick) { + consumed = true; + } + + return consumed; +} + +void evil_portal_scene_console_output_on_exit(void *context) { + Evil_PortalApp *app = context; + + // Unregister rx callback + evil_portal_uart_set_handle_rx_data_cb(app->uart, NULL); +} diff --git a/applications/external/evil_portal/scenes/evil_portal_scene_start.c b/applications/external/evil_portal/scenes/evil_portal_scene_start.c new file mode 100644 index 000000000..6de5af083 --- /dev/null +++ b/applications/external/evil_portal/scenes/evil_portal_scene_start.c @@ -0,0 +1,158 @@ +#include "../evil_portal_app_i.h" + +// For each command, define whether additional arguments are needed +// (enabling text input to fill them out), and whether the console +// text box should focus at the start of the output or the end +typedef enum { NO_ARGS = 0, INPUT_ARGS, TOGGLE_ARGS } InputArgs; + +typedef enum { + FOCUS_CONSOLE_END = 0, + FOCUS_CONSOLE_START, + FOCUS_CONSOLE_TOGGLE +} FocusConsole; + +#define SHOW_STOPSCAN_TIP (true) +#define NO_TIP (false) + +#define MAX_OPTIONS (9) +typedef struct { + const char *item_string; + const char *options_menu[MAX_OPTIONS]; + int num_options_menu; + const char *actual_commands[MAX_OPTIONS]; + InputArgs needs_keyboard; + FocusConsole focus_console; + bool show_stopscan_tip; +} Evil_PortalItem; + +// NUM_MENU_ITEMS defined in evil_portal_app_i.h - if you add an entry here, +// increment it! +const Evil_PortalItem items[NUM_MENU_ITEMS] = { + // send command + {"Start portal", + {""}, + 1, + {SET_HTML_CMD}, + NO_ARGS, + FOCUS_CONSOLE_END, + SHOW_STOPSCAN_TIP}, + + // stop portal + {"Stop portal", {""}, 1, {RESET_CMD}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP}, + + // console + {"Save logs", + {""}, + 1, + {"savelogs"}, + NO_ARGS, + FOCUS_CONSOLE_START, + SHOW_STOPSCAN_TIP}, + + // help + {"Help", + {""}, + 1, + {"help"}, + NO_ARGS, + FOCUS_CONSOLE_START, + SHOW_STOPSCAN_TIP}, +}; + +static void evil_portal_scene_start_var_list_enter_callback(void *context, + uint32_t index) { + furi_assert(context); + Evil_PortalApp *app = context; + + furi_assert(index < NUM_MENU_ITEMS); + const Evil_PortalItem *item = &items[index]; + + 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]; + app->is_command = true; + app->is_custom_tx_string = false; + app->selected_menu_index = index; + app->focus_console_start = (item->focus_console == FOCUS_CONSOLE_TOGGLE) + ? (selected_option_index == 0) + : item->focus_console; + app->show_stopscan_tip = item->show_stopscan_tip; + + view_dispatcher_send_custom_event(app->view_dispatcher, + Evil_PortalEventStartConsole); +} + +static void +evil_portal_scene_start_var_list_change_callback(VariableItem *item) { + furi_assert(item); + + Evil_PortalApp *app = variable_item_get_context(item); + furi_assert(app); + + const Evil_PortalItem *menu_item = &items[app->selected_menu_index]; + uint8_t item_index = variable_item_get_current_value_index(item); + furi_assert(item_index < menu_item->num_options_menu); + variable_item_set_current_value_text(item, + menu_item->options_menu[item_index]); + app->selected_option_index[app->selected_menu_index] = item_index; +} + +void evil_portal_scene_start_on_enter(void *context) { + Evil_PortalApp *app = context; + VariableItemList *var_item_list = app->var_item_list; + + variable_item_list_set_enter_callback( + var_item_list, evil_portal_scene_start_var_list_enter_callback, app); + + VariableItem *item; + for (int i = 0; i < NUM_MENU_ITEMS; ++i) { + item = variable_item_list_add( + var_item_list, items[i].item_string, items[i].num_options_menu, + evil_portal_scene_start_var_list_change_callback, app); + variable_item_set_current_value_index(item, app->selected_option_index[i]); + variable_item_set_current_value_text( + item, items[i].options_menu[app->selected_option_index[i]]); + } + + variable_item_list_set_selected_item( + var_item_list, + scene_manager_get_scene_state(app->scene_manager, Evil_PortalSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, + Evil_PortalAppViewVarItemList); +} + +bool evil_portal_scene_start_on_event(void *context, SceneManagerEvent event) { + UNUSED(context); + Evil_PortalApp *app = context; + bool consumed = false; + + if (event.type == SceneManagerEventTypeCustom) { + if (event.event == Evil_PortalEventStartPortal) { + scene_manager_set_scene_state(app->scene_manager, Evil_PortalSceneStart, + app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, + Evil_PortalAppViewStartPortal); + } else if (event.event == Evil_PortalEventStartKeyboard) { + scene_manager_set_scene_state(app->scene_manager, Evil_PortalSceneStart, + app->selected_menu_index); + } else if (event.event == Evil_PortalEventStartConsole) { + scene_manager_set_scene_state(app->scene_manager, Evil_PortalSceneStart, + app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, + Evil_PortalAppViewConsoleOutput); + } + consumed = true; + } else if (event.type == SceneManagerEventTypeTick) { + app->selected_menu_index = + variable_item_list_get_selected_item_index(app->var_item_list); + consumed = true; + } + + return consumed; +} + +void evil_portal_scene_start_on_exit(void *context) { + Evil_PortalApp *app = context; + variable_item_list_reset(app->var_item_list); +} diff --git a/assets/resources/apps_data/evil_portal/ap.config.txt b/assets/resources/apps_data/evil_portal/ap.config.txt new file mode 100644 index 000000000..a8d23beee --- /dev/null +++ b/assets/resources/apps_data/evil_portal/ap.config.txt @@ -0,0 +1 @@ +Google Free WiFi \ No newline at end of file diff --git a/assets/resources/apps_data/evil_portal/index.html b/assets/resources/apps_data/evil_portal/index.html new file mode 100644 index 000000000..41f674991 --- /dev/null +++ b/assets/resources/apps_data/evil_portal/index.html @@ -0,0 +1 @@ +
\ No newline at end of file