seos.c 10 KB

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