seos.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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_load_keys(seos);
  104. return seos;
  105. }
  106. void seos_free(Seos* seos) {
  107. furi_assert(seos);
  108. furi_hal_power_disable_otg();
  109. nfc_free(seos->nfc);
  110. // Nfc device
  111. nfc_device_free(seos->nfc_device);
  112. // Submenu
  113. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewMenu);
  114. submenu_free(seos->submenu);
  115. // Popup
  116. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewPopup);
  117. popup_free(seos->popup);
  118. // Loading
  119. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewLoading);
  120. loading_free(seos->loading);
  121. // TextInput
  122. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewTextInput);
  123. text_input_free(seos->text_input);
  124. // TextBox
  125. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewTextBox);
  126. text_box_free(seos->text_box);
  127. furi_string_free(seos->text_box_store);
  128. // Custom Widget
  129. view_dispatcher_remove_view(seos->view_dispatcher, SeosViewWidget);
  130. widget_free(seos->widget);
  131. // View Dispatcher
  132. view_dispatcher_free(seos->view_dispatcher);
  133. // Scene Manager
  134. scene_manager_free(seos->scene_manager);
  135. // GUI
  136. furi_record_close(RECORD_GUI);
  137. seos->gui = NULL;
  138. // Notifications
  139. furi_record_close(RECORD_NOTIFICATION);
  140. seos->notifications = NULL;
  141. furi_string_free(seos->load_path);
  142. furi_record_close(RECORD_STORAGE);
  143. furi_record_close(RECORD_DIALOGS);
  144. if(seos->seos_emulator) {
  145. seos_emulator_free(seos->seos_emulator);
  146. seos->seos_emulator = NULL;
  147. }
  148. free(seos);
  149. }
  150. void seos_text_store_set(Seos* seos, const char* text, ...) {
  151. va_list args;
  152. va_start(args, text);
  153. vsnprintf(seos->text_store, sizeof(seos->text_store), text, args);
  154. va_end(args);
  155. }
  156. void seos_text_store_clear(Seos* seos) {
  157. memset(seos->text_store, 0, sizeof(seos->text_store));
  158. }
  159. bool seos_credential_save(Seos* seos, const char* dev_name) {
  160. bool saved = false;
  161. FlipperFormat* file = flipper_format_file_alloc(seos->storage);
  162. FuriString* temp_str = furi_string_alloc();
  163. bool use_load_path = true;
  164. do {
  165. if(use_load_path && !furi_string_empty(seos->load_path)) {
  166. // Get directory name
  167. path_extract_dirname(furi_string_get_cstr(seos->load_path), temp_str);
  168. // Make path to file to save
  169. furi_string_cat_printf(temp_str, "/%s%s", dev_name, SEOS_APP_EXTENSION);
  170. } else {
  171. // First remove file if it was saved
  172. furi_string_printf(
  173. temp_str, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, dev_name, SEOS_APP_EXTENSION);
  174. }
  175. // Open file
  176. if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
  177. // Write header
  178. if(!flipper_format_write_header_cstr(file, seos_file_header, seos_file_version)) break;
  179. if(!flipper_format_write_uint32(
  180. file, "Diversifier Length", (uint32_t*)&(seos->credential.diversifier_len), 1))
  181. break;
  182. if(!flipper_format_write_hex(
  183. file, "Diversifier", seos->credential.diversifier, seos->credential.diversifier_len))
  184. break;
  185. if(!flipper_format_write_uint32(
  186. file, "SIO Length", (uint32_t*)&(seos->credential.sio_len), 1))
  187. break;
  188. if(!flipper_format_write_hex(file, "SIO", seos->credential.sio, seos->credential.sio_len))
  189. break;
  190. saved = true;
  191. } while(false);
  192. if(!saved) {
  193. dialog_message_show_storage_error(seos->dialogs, "Can not save\nfile");
  194. }
  195. furi_string_free(temp_str);
  196. flipper_format_free(file);
  197. return saved;
  198. }
  199. static const NotificationSequence seos_sequence_blink_start_blue = {
  200. &message_blink_start_10,
  201. &message_blink_set_color_blue,
  202. &message_do_not_reset,
  203. NULL,
  204. };
  205. static const NotificationSequence seos_sequence_blink_stop = {
  206. &message_blink_stop,
  207. NULL,
  208. };
  209. void seos_blink_start(Seos* seos) {
  210. notification_message(seos->notifications, &seos_sequence_blink_start_blue);
  211. }
  212. void seos_blink_stop(Seos* seos) {
  213. notification_message(seos->notifications, &seos_sequence_blink_stop);
  214. }
  215. void seos_show_loading_popup(void* context, bool show) {
  216. Seos* seos = context;
  217. if(show) {
  218. // Raise timer priority so that animations can play
  219. furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
  220. view_dispatcher_switch_to_view(seos->view_dispatcher, SeosViewLoading);
  221. } else {
  222. // Restore default timer priority
  223. furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
  224. }
  225. }
  226. int32_t seos_app(void* p) {
  227. UNUSED(p);
  228. Seos* seos = seos_alloc();
  229. scene_manager_next_scene(seos->scene_manager, SeosSceneStart);
  230. view_dispatcher_run(seos->view_dispatcher);
  231. seos_free(seos);
  232. return 0;
  233. }