weebo.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #include "weebo_i.h"
  2. #define TAG "weebo"
  3. #define WEEBO_KEY_RETAIL_FILENAME "key_retail"
  4. /*
  5. uint8_t original[NTAG215_SIZE];
  6. uint8_t plain_base[NFC3D_AMIIBO_SIZE];
  7. uint8_t modified[NTAG215_SIZE];
  8. void calculate_pwd(uint8_t* uid, uint8_t* pwd) {
  9. pwd[0] = uid[1] ^ uid[3] ^ 0xAA;
  10. pwd[1] = uid[2] ^ uid[4] ^ 0x55;
  11. pwd[2] = uid[3] ^ uid[5] ^ 0xAA;
  12. pwd[3] = uid[4] ^ uid[6] ^ 0x55;
  13. }
  14. */
  15. bool weebo_load_key_retail(Weebo* weebo) {
  16. FuriString* path = furi_string_alloc();
  17. bool parsed = false;
  18. uint8_t buffer[160];
  19. memset(buffer, 0, sizeof(buffer));
  20. Storage* storage = furi_record_open(RECORD_STORAGE);
  21. Stream* stream = file_stream_alloc(storage);
  22. do {
  23. furi_string_printf(
  24. path, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, WEEBO_KEY_RETAIL_FILENAME, ".bin");
  25. bool opened =
  26. file_stream_open(stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING);
  27. if(!opened) {
  28. FURI_LOG_E(TAG, "Failed to open file");
  29. break;
  30. }
  31. size_t bytes_read = stream_read(stream, buffer, sizeof(buffer));
  32. if(bytes_read != sizeof(buffer)) {
  33. FURI_LOG_E(TAG, "Insufficient data");
  34. break;
  35. }
  36. memcpy(&weebo->amiiboKeys, buffer, bytes_read);
  37. // TODO: compare SHA1
  38. parsed = true;
  39. } while(false);
  40. file_stream_close(stream);
  41. furi_record_close(RECORD_STORAGE);
  42. furi_string_free(path);
  43. return parsed;
  44. }
  45. bool weebo_load_figure(Weebo* weebo, FuriString* path, bool show_dialog) {
  46. bool parsed = false;
  47. uint8_t buffer[NTAG215_SIZE];
  48. memset(buffer, 0, sizeof(buffer));
  49. Storage* storage = furi_record_open(RECORD_STORAGE);
  50. Stream* stream = file_stream_alloc(storage);
  51. if(weebo->loading_cb) {
  52. weebo->loading_cb(weebo->loading_cb_ctx, true);
  53. }
  54. // TODO: reject if the selected file is key_retail
  55. do {
  56. bool opened =
  57. file_stream_open(stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING);
  58. if(!opened) {
  59. FURI_LOG_E(TAG, "Failed to open file");
  60. break;
  61. }
  62. size_t bytes_read = stream_read(stream, buffer, sizeof(buffer));
  63. if(bytes_read != sizeof(buffer)) {
  64. FURI_LOG_E(TAG, "Insufficient data");
  65. break;
  66. }
  67. if(!nfc3d_amiibo_unpack(&weebo->amiiboKeys, buffer, weebo->figure)) {
  68. FURI_LOG_E(TAG, "Failed to unpack");
  69. break;
  70. }
  71. parsed = true;
  72. } while(false);
  73. file_stream_close(stream);
  74. furi_record_close(RECORD_STORAGE);
  75. if(weebo->loading_cb) {
  76. weebo->loading_cb(weebo->loading_cb_ctx, false);
  77. }
  78. if((!parsed) && (show_dialog)) {
  79. dialog_message_show_storage_error(weebo->dialogs, "Can not parse\nfile");
  80. }
  81. return parsed;
  82. }
  83. void weebo_set_loading_callback(Weebo* weebo, WeeboLoadingCallback callback, void* context) {
  84. furi_assert(weebo);
  85. weebo->loading_cb = callback;
  86. weebo->loading_cb_ctx = context;
  87. }
  88. bool weebo_file_select(Weebo* weebo) {
  89. furi_assert(weebo);
  90. bool res = false;
  91. FuriString* weebo_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
  92. DialogsFileBrowserOptions browser_options;
  93. dialog_file_browser_set_basic_options(&browser_options, ".bin", &I_Nfc_10px);
  94. browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
  95. res = dialog_file_browser_show(
  96. weebo->dialogs, weebo->load_path, weebo_app_folder, &browser_options);
  97. furi_string_free(weebo_app_folder);
  98. if(res) {
  99. FuriString* filename;
  100. filename = furi_string_alloc();
  101. path_extract_filename(weebo->load_path, filename, true);
  102. strncpy(weebo->file_name, furi_string_get_cstr(filename), WEEBO_FILE_NAME_MAX_LENGTH);
  103. res = weebo_load_figure(weebo, weebo->load_path, true);
  104. furi_string_free(filename);
  105. }
  106. return res;
  107. }
  108. bool weebo_custom_event_callback(void* context, uint32_t event) {
  109. furi_assert(context);
  110. Weebo* weebo = context;
  111. return scene_manager_handle_custom_event(weebo->scene_manager, event);
  112. }
  113. bool weebo_back_event_callback(void* context) {
  114. furi_assert(context);
  115. Weebo* weebo = context;
  116. return scene_manager_handle_back_event(weebo->scene_manager);
  117. }
  118. void weebo_tick_event_callback(void* context) {
  119. furi_assert(context);
  120. Weebo* weebo = context;
  121. scene_manager_handle_tick_event(weebo->scene_manager);
  122. }
  123. Weebo* weebo_alloc() {
  124. Weebo* weebo = malloc(sizeof(Weebo));
  125. weebo->view_dispatcher = view_dispatcher_alloc();
  126. weebo->scene_manager = scene_manager_alloc(&weebo_scene_handlers, weebo);
  127. view_dispatcher_set_event_callback_context(weebo->view_dispatcher, weebo);
  128. view_dispatcher_set_custom_event_callback(weebo->view_dispatcher, weebo_custom_event_callback);
  129. view_dispatcher_set_navigation_event_callback(
  130. weebo->view_dispatcher, weebo_back_event_callback);
  131. view_dispatcher_set_tick_event_callback(
  132. weebo->view_dispatcher, weebo_tick_event_callback, 100);
  133. weebo->nfc = nfc_alloc();
  134. // Nfc device
  135. weebo->nfc_device = nfc_device_alloc();
  136. nfc_device_set_loading_callback(weebo->nfc_device, weebo_show_loading_popup, weebo);
  137. // Open GUI record
  138. weebo->gui = furi_record_open(RECORD_GUI);
  139. view_dispatcher_attach_to_gui(
  140. weebo->view_dispatcher, weebo->gui, ViewDispatcherTypeFullscreen);
  141. // Open Notification record
  142. weebo->notifications = furi_record_open(RECORD_NOTIFICATION);
  143. // Submenu
  144. weebo->submenu = submenu_alloc();
  145. view_dispatcher_add_view(
  146. weebo->view_dispatcher, WeeboViewMenu, submenu_get_view(weebo->submenu));
  147. // Popup
  148. weebo->popup = popup_alloc();
  149. view_dispatcher_add_view(weebo->view_dispatcher, WeeboViewPopup, popup_get_view(weebo->popup));
  150. // Loading
  151. weebo->loading = loading_alloc();
  152. view_dispatcher_add_view(
  153. weebo->view_dispatcher, WeeboViewLoading, loading_get_view(weebo->loading));
  154. // Text Input
  155. weebo->text_input = text_input_alloc();
  156. view_dispatcher_add_view(
  157. weebo->view_dispatcher, WeeboViewTextInput, text_input_get_view(weebo->text_input));
  158. // Number Input
  159. weebo->number_input = number_input_alloc();
  160. view_dispatcher_add_view(
  161. weebo->view_dispatcher, WeeboViewNumberInput, number_input_get_view(weebo->number_input));
  162. // TextBox
  163. weebo->text_box = text_box_alloc();
  164. view_dispatcher_add_view(
  165. weebo->view_dispatcher, WeeboViewTextBox, text_box_get_view(weebo->text_box));
  166. weebo->text_box_store = furi_string_alloc();
  167. // Custom Widget
  168. weebo->widget = widget_alloc();
  169. view_dispatcher_add_view(
  170. weebo->view_dispatcher, WeeboViewWidget, widget_get_view(weebo->widget));
  171. weebo->storage = furi_record_open(RECORD_STORAGE);
  172. weebo->dialogs = furi_record_open(RECORD_DIALOGS);
  173. weebo->load_path = furi_string_alloc();
  174. weebo->keys_loaded = false;
  175. return weebo;
  176. }
  177. void weebo_free(Weebo* weebo) {
  178. furi_assert(weebo);
  179. nfc_free(weebo->nfc);
  180. // Nfc device
  181. nfc_device_free(weebo->nfc_device);
  182. // Submenu
  183. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewMenu);
  184. submenu_free(weebo->submenu);
  185. // Popup
  186. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewPopup);
  187. popup_free(weebo->popup);
  188. // Loading
  189. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewLoading);
  190. loading_free(weebo->loading);
  191. // TextInput
  192. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewTextInput);
  193. text_input_free(weebo->text_input);
  194. // NumberInput
  195. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewNumberInput);
  196. number_input_free(weebo->number_input);
  197. // TextBox
  198. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewTextBox);
  199. text_box_free(weebo->text_box);
  200. furi_string_free(weebo->text_box_store);
  201. // Custom Widget
  202. view_dispatcher_remove_view(weebo->view_dispatcher, WeeboViewWidget);
  203. widget_free(weebo->widget);
  204. // View Dispatcher
  205. view_dispatcher_free(weebo->view_dispatcher);
  206. // Scene Manager
  207. scene_manager_free(weebo->scene_manager);
  208. // GUI
  209. furi_record_close(RECORD_GUI);
  210. weebo->gui = NULL;
  211. // Notifications
  212. furi_record_close(RECORD_NOTIFICATION);
  213. weebo->notifications = NULL;
  214. furi_string_free(weebo->load_path);
  215. furi_record_close(RECORD_STORAGE);
  216. furi_record_close(RECORD_DIALOGS);
  217. free(weebo);
  218. }
  219. void weebo_text_store_set(Weebo* weebo, const char* text, ...) {
  220. va_list args;
  221. va_start(args, text);
  222. vsnprintf(weebo->text_store, sizeof(weebo->text_store), text, args);
  223. va_end(args);
  224. }
  225. void weebo_text_store_clear(Weebo* weebo) {
  226. memset(weebo->text_store, 0, sizeof(weebo->text_store));
  227. }
  228. static const NotificationSequence weebo_sequence_blink_start_blue = {
  229. &message_blink_start_10,
  230. &message_blink_set_color_blue,
  231. &message_do_not_reset,
  232. NULL,
  233. };
  234. static const NotificationSequence weebo_sequence_blink_stop = {
  235. &message_blink_stop,
  236. NULL,
  237. };
  238. void weebo_blink_start(Weebo* weebo) {
  239. notification_message(weebo->notifications, &weebo_sequence_blink_start_blue);
  240. }
  241. void weebo_blink_stop(Weebo* weebo) {
  242. notification_message(weebo->notifications, &weebo_sequence_blink_stop);
  243. }
  244. void weebo_show_loading_popup(void* context, bool show) {
  245. Weebo* weebo = context;
  246. if(show) {
  247. // Raise timer priority so that animations can play
  248. furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
  249. view_dispatcher_switch_to_view(weebo->view_dispatcher, WeeboViewLoading);
  250. } else {
  251. // Restore default timer priority
  252. furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
  253. }
  254. }
  255. int32_t weebo_app(void* p) {
  256. UNUSED(p);
  257. Weebo* weebo = weebo_alloc();
  258. weebo->keys_loaded = weebo_load_key_retail(weebo);
  259. if(weebo->keys_loaded) {
  260. scene_manager_next_scene(weebo->scene_manager, WeeboSceneMainMenu);
  261. } else {
  262. scene_manager_next_scene(weebo->scene_manager, WeeboSceneKeysMissing);
  263. }
  264. view_dispatcher_run(weebo->view_dispatcher);
  265. weebo_free(weebo);
  266. return 0;
  267. }