seos.c 11 KB

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