seos.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #include "seos_i.h"
  2. #define TAG "Seos"
  3. #define SEOS_KEYS_FILENAME "keys"
  4. static void seos_ble_connection_status_callback(BtStatus status, void* context) {
  5. furi_assert(context);
  6. Seos* seos = context;
  7. UNUSED(seos);
  8. FURI_LOG_D(TAG, "seos_ble_connection_status_callback %d", (status == BtStatusConnected));
  9. /*
  10. ble_hid->is_connected = (status == BtStatusConnected);
  11. if(ble_hid->state_callback) {
  12. ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
  13. }
  14. */
  15. }
  16. bool seos_load_keys(Seos* seos) {
  17. const char* file_header = "Seos keys";
  18. const uint32_t file_version = 1;
  19. bool parsed = false;
  20. FlipperFormat* file = flipper_format_file_alloc(seos->storage);
  21. FuriString* path = furi_string_alloc();
  22. FuriString* temp_str = furi_string_alloc();
  23. uint32_t version = 0;
  24. do {
  25. furi_string_printf(
  26. path, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, SEOS_KEYS_FILENAME, ".txt");
  27. // Open file
  28. if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
  29. if(!flipper_format_read_header(file, temp_str, &version)) break;
  30. if(!furi_string_equal_str(temp_str, file_header) || (version != file_version)) {
  31. break;
  32. }
  33. if(!flipper_format_read_uint32(file, "SEOS_ADF_OID_LEN", (uint32_t*)&SEOS_ADF_OID_LEN, 1))
  34. break;
  35. if(!flipper_format_read_hex(file, "SEOS_ADF_OID", SEOS_ADF_OID, SEOS_ADF_OID_LEN)) break;
  36. if(!flipper_format_read_hex(file, "SEOS_ADF1_PRIV_ENC", SEOS_ADF1_PRIV_ENC, 16)) break;
  37. if(!flipper_format_read_hex(file, "SEOS_ADF1_PRIV_MAC", SEOS_ADF1_PRIV_MAC, 16)) break;
  38. if(!flipper_format_read_hex(file, "SEOS_ADF1_READ", SEOS_ADF1_READ, 16)) break;
  39. parsed = true;
  40. } while(false);
  41. if(parsed) {
  42. FURI_LOG_I(TAG, "Keys loaded");
  43. BitBuffer* tmp = bit_buffer_alloc(SEOS_ADF_OID_LEN);
  44. bit_buffer_append_bytes(tmp, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  45. seos_log_bitbuffer(TAG, "Keys for ADF OID loaded", tmp);
  46. bit_buffer_free(tmp);
  47. } else {
  48. FURI_LOG_I(TAG, "Using default keys");
  49. }
  50. furi_string_free(path);
  51. furi_string_free(temp_str);
  52. flipper_format_free(file);
  53. return parsed;
  54. }
  55. bool seos_custom_event_callback(void* context, uint32_t event) {
  56. furi_assert(context);
  57. Seos* seos = context;
  58. return scene_manager_handle_custom_event(seos->scene_manager, event);
  59. }
  60. bool seos_back_event_callback(void* context) {
  61. furi_assert(context);
  62. Seos* seos = context;
  63. return scene_manager_handle_back_event(seos->scene_manager);
  64. }
  65. void seos_tick_event_callback(void* context) {
  66. furi_assert(context);
  67. Seos* seos = context;
  68. scene_manager_handle_tick_event(seos->scene_manager);
  69. }
  70. Seos* seos_alloc() {
  71. Seos* seos = malloc(sizeof(Seos));
  72. seos->has_ble = false;
  73. furi_hal_power_enable_otg();
  74. seos->view_dispatcher = view_dispatcher_alloc();
  75. seos->scene_manager = scene_manager_alloc(&seos_scene_handlers, seos);
  76. view_dispatcher_set_event_callback_context(seos->view_dispatcher, seos);
  77. view_dispatcher_set_custom_event_callback(seos->view_dispatcher, seos_custom_event_callback);
  78. view_dispatcher_set_navigation_event_callback(seos->view_dispatcher, seos_back_event_callback);
  79. view_dispatcher_set_tick_event_callback(seos->view_dispatcher, seos_tick_event_callback, 100);
  80. seos->nfc = nfc_alloc();
  81. // Nfc device
  82. seos->nfc_device = nfc_device_alloc();
  83. nfc_device_set_loading_callback(seos->nfc_device, seos_show_loading_popup, seos);
  84. // Open GUI record
  85. seos->gui = furi_record_open(RECORD_GUI);
  86. view_dispatcher_attach_to_gui(seos->view_dispatcher, seos->gui, ViewDispatcherTypeFullscreen);
  87. // Open Notification record
  88. seos->notifications = furi_record_open(RECORD_NOTIFICATION);
  89. // Submenu
  90. seos->submenu = submenu_alloc();
  91. view_dispatcher_add_view(seos->view_dispatcher, SeosViewMenu, submenu_get_view(seos->submenu));
  92. // Popup
  93. seos->popup = popup_alloc();
  94. view_dispatcher_add_view(seos->view_dispatcher, SeosViewPopup, popup_get_view(seos->popup));
  95. // Loading
  96. seos->loading = loading_alloc();
  97. view_dispatcher_add_view(
  98. seos->view_dispatcher, SeosViewLoading, loading_get_view(seos->loading));
  99. // Text Input
  100. seos->text_input = text_input_alloc();
  101. view_dispatcher_add_view(
  102. seos->view_dispatcher, SeosViewTextInput, text_input_get_view(seos->text_input));
  103. // TextBox
  104. seos->text_box = text_box_alloc();
  105. view_dispatcher_add_view(
  106. seos->view_dispatcher, SeosViewTextBox, text_box_get_view(seos->text_box));
  107. seos->text_box_store = furi_string_alloc();
  108. // Custom Widget
  109. seos->widget = widget_alloc();
  110. view_dispatcher_add_view(seos->view_dispatcher, SeosViewWidget, widget_get_view(seos->widget));
  111. seos->storage = furi_record_open(RECORD_STORAGE);
  112. seos->dialogs = furi_record_open(RECORD_DIALOGS);
  113. seos->load_path = furi_string_alloc();
  114. seos->seos_emulator = seos_emulator_alloc(&seos->credential);
  115. seos->keys_loaded = seos_load_keys(seos);
  116. seos->bt = furi_record_open(RECORD_BT);
  117. bt_disconnect(seos->bt);
  118. // Wait 2nd core to update nvm storage
  119. furi_delay_ms(200);
  120. seos->ble_profile = bt_profile_start(seos->bt, ble_profile_seos, NULL);
  121. furi_check(seos->ble_profile);
  122. bt_set_status_changed_callback(seos->bt, seos_ble_connection_status_callback, seos);
  123. furi_hal_bt_start_advertising();
  124. return seos;
  125. }
  126. void seos_free(Seos* seos) {
  127. furi_assert(seos);
  128. furi_hal_power_disable_otg();
  129. nfc_free(seos->nfc);
  130. // Nfc device
  131. nfc_device_free(seos->nfc_device);
  132. // Submenu
  133. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewMenu);
  134. submenu_free(seos->submenu);
  135. // Popup
  136. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewPopup);
  137. popup_free(seos->popup);
  138. // Loading
  139. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewLoading);
  140. loading_free(seos->loading);
  141. // TextInput
  142. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewTextInput);
  143. text_input_free(seos->text_input);
  144. // TextBox
  145. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewTextBox);
  146. text_box_free(seos->text_box);
  147. furi_string_free(seos->text_box_store);
  148. // Custom Widget
  149. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewWidget);
  150. widget_free(seos->widget);
  151. // View Dispatcher
  152. view_dispatcher_free(seos->view_dispatcher);
  153. // Scene Manager
  154. scene_manager_free(seos->scene_manager);
  155. // GUI
  156. furi_record_close(RECORD_GUI);
  157. seos->gui = NULL;
  158. // Notifications
  159. furi_record_close(RECORD_NOTIFICATION);
  160. seos->notifications = NULL;
  161. furi_string_free(seos->load_path);
  162. furi_record_close(RECORD_STORAGE);
  163. furi_record_close(RECORD_DIALOGS);
  164. if(seos->seos_emulator) {
  165. seos_emulator_free(seos->seos_emulator);
  166. seos->seos_emulator = NULL;
  167. }
  168. furi_hal_bt_stop_advertising();
  169. bt_set_status_changed_callback(seos->bt, NULL, NULL);
  170. bt_disconnect(seos->bt);
  171. // Wait 2nd core to update nvm storage
  172. furi_delay_ms(200);
  173. bt_keys_storage_set_default_path(seos->bt);
  174. furi_check(bt_profile_restore_default(seos->bt));
  175. furi_record_close(RECORD_BT);
  176. free(seos);
  177. }
  178. void seos_text_store_set(Seos* seos, const char* text, ...) {
  179. va_list args;
  180. va_start(args, text);
  181. vsnprintf(seos->text_store, sizeof(seos->text_store), text, args);
  182. va_end(args);
  183. }
  184. void seos_text_store_clear(Seos* seos) {
  185. memset(seos->text_store, 0, sizeof(seos->text_store));
  186. }
  187. bool seos_credential_save(Seos* seos, const char* dev_name) {
  188. bool saved = false;
  189. FlipperFormat* file = flipper_format_file_alloc(seos->storage);
  190. FuriString* temp_str = furi_string_alloc();
  191. bool use_load_path = true;
  192. do {
  193. if(use_load_path && !furi_string_empty(seos->load_path)) {
  194. // Get directory name
  195. path_extract_dirname(furi_string_get_cstr(seos->load_path), temp_str);
  196. // Make path to file to save
  197. furi_string_cat_printf(temp_str, "/%s%s", dev_name, SEOS_APP_EXTENSION);
  198. } else {
  199. // First remove file if it was saved
  200. furi_string_printf(
  201. temp_str, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, dev_name, SEOS_APP_EXTENSION);
  202. }
  203. // Open file
  204. if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
  205. // Write header
  206. if(!flipper_format_write_header_cstr(file, seos_file_header, seos_file_version)) break;
  207. if(!flipper_format_write_uint32(
  208. file, "Diversifier Length", (uint32_t*)&(seos->credential.diversifier_len), 1))
  209. break;
  210. if(!flipper_format_write_hex(
  211. file, "Diversifier", seos->credential.diversifier, seos->credential.diversifier_len))
  212. break;
  213. if(!flipper_format_write_uint32(
  214. file, "SIO Length", (uint32_t*)&(seos->credential.sio_len), 1))
  215. break;
  216. if(!flipper_format_write_hex(file, "SIO", seos->credential.sio, seos->credential.sio_len))
  217. break;
  218. saved = true;
  219. } while(false);
  220. if(!saved) {
  221. dialog_message_show_storage_error(seos->dialogs, "Can not save\nfile");
  222. }
  223. furi_string_free(temp_str);
  224. flipper_format_free(file);
  225. return saved;
  226. }
  227. static const NotificationSequence seos_sequence_blink_start_blue = {
  228. &message_blink_start_10,
  229. &message_blink_set_color_blue,
  230. &message_do_not_reset,
  231. NULL,
  232. };
  233. static const NotificationSequence seos_sequence_blink_stop = {
  234. &message_blink_stop,
  235. NULL,
  236. };
  237. void seos_blink_start(Seos* seos) {
  238. notification_message(seos->notifications, &seos_sequence_blink_start_blue);
  239. }
  240. void seos_blink_stop(Seos* seos) {
  241. notification_message(seos->notifications, &seos_sequence_blink_stop);
  242. }
  243. void seos_show_loading_popup(void* context, bool show) {
  244. Seos* seos = context;
  245. if(show) {
  246. // Raise timer priority so that animations can play
  247. furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
  248. view_dispatcher_switch_to_view(seos->view_dispatcher, SeosViewLoading);
  249. } else {
  250. // Restore default timer priority
  251. furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
  252. }
  253. }
  254. int32_t seos_app(void* p) {
  255. UNUSED(p);
  256. Seos* seos = seos_alloc();
  257. if(seos->keys_loaded) {
  258. scene_manager_next_scene(seos->scene_manager, SeosSceneMainMenu);
  259. } else {
  260. scene_manager_next_scene(seos->scene_manager, SeosSceneZeroKeys);
  261. }
  262. view_dispatcher_run(seos->view_dispatcher);
  263. seos_free(seos);
  264. return 0;
  265. }