totp_scene_authenticate.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include "totp_scene_authenticate.h"
  2. #include <dialogs/dialogs.h>
  3. #include <totp_icons.h>
  4. #if __has_include(<assets_icons.h>)
  5. #include <assets_icons.h>
  6. #endif
  7. #include "../../../types/common.h"
  8. #include "../../constants.h"
  9. #include "../../../services/config/config.h"
  10. #include "../../scene_director.h"
  11. #include "../../totp_scenes_enum.h"
  12. #include "../../../services/crypto/crypto_facade.h"
  13. #include "../../../types/user_pin_codes.h"
  14. #include <assets_icons.h>
  15. #define MAX_CODE_LENGTH CRYPTO_IV_LENGTH
  16. static const uint8_t PIN_ASTERISK_RADIUS = 3;
  17. static const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
  18. typedef struct {
  19. TotpUserPinCode code_input[MAX_CODE_LENGTH];
  20. uint8_t code_length;
  21. } SceneState;
  22. void totp_scene_authenticate_activate(PluginState* plugin_state) {
  23. SceneState* scene_state = malloc(sizeof(SceneState));
  24. furi_check(scene_state != NULL);
  25. scene_state->code_length = 0;
  26. memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
  27. plugin_state->current_scene_state = scene_state;
  28. memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
  29. }
  30. void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
  31. const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
  32. int v_shift = 0;
  33. if(scene_state->code_length > 0) {
  34. v_shift = -10;
  35. }
  36. if(plugin_state->crypto_settings.crypto_verify_data == NULL) {
  37. canvas_draw_str_aligned(
  38. canvas,
  39. SCREEN_WIDTH_CENTER,
  40. SCREEN_HEIGHT_CENTER - 10 + v_shift,
  41. AlignCenter,
  42. AlignCenter,
  43. "Use arrow keys");
  44. canvas_draw_str_aligned(
  45. canvas,
  46. SCREEN_WIDTH_CENTER,
  47. SCREEN_HEIGHT_CENTER + 5 + v_shift,
  48. AlignCenter,
  49. AlignCenter,
  50. "to setup new PIN");
  51. } else {
  52. canvas_draw_str_aligned(
  53. canvas,
  54. SCREEN_WIDTH_CENTER,
  55. SCREEN_HEIGHT_CENTER + v_shift,
  56. AlignCenter,
  57. AlignCenter,
  58. "Use arrow keys to enter PIN");
  59. }
  60. if(scene_state->code_length > 0) {
  61. uint8_t left_start_x = ((scene_state->code_length - 1) * PIN_ASTERISK_STEP) >> 1;
  62. for(uint8_t i = 0; i < scene_state->code_length; i++) {
  63. canvas_draw_disc(
  64. canvas,
  65. SCREEN_WIDTH_CENTER - left_start_x + i * PIN_ASTERISK_STEP,
  66. SCREEN_HEIGHT_CENTER + 10,
  67. PIN_ASTERISK_RADIUS);
  68. }
  69. }
  70. }
  71. bool totp_scene_authenticate_handle_event(
  72. const PluginEvent* const event,
  73. PluginState* plugin_state) {
  74. if(event->type != EventTypeKey) {
  75. return true;
  76. }
  77. if(event->input.type == InputTypeShort && event->input.key == InputKeyBack) {
  78. return false;
  79. }
  80. SceneState* scene_state = plugin_state->current_scene_state;
  81. if((event->input.type == InputTypeLong || event->input.type == InputTypeRepeat) &&
  82. event->input.key == InputKeyBack) {
  83. if(scene_state->code_length > 0) {
  84. scene_state->code_input[scene_state->code_length - 1] = 0;
  85. scene_state->code_length--;
  86. }
  87. } else if(event->input.type == InputTypePress) {
  88. switch(event->input.key) {
  89. case InputKeyUp:
  90. if(scene_state->code_length < MAX_CODE_LENGTH) {
  91. scene_state->code_input[scene_state->code_length] = PinCodeArrowUp;
  92. scene_state->code_length++;
  93. }
  94. break;
  95. case InputKeyDown:
  96. if(scene_state->code_length < MAX_CODE_LENGTH) {
  97. scene_state->code_input[scene_state->code_length] = PinCodeArrowDown;
  98. scene_state->code_length++;
  99. }
  100. break;
  101. case InputKeyRight:
  102. if(scene_state->code_length < MAX_CODE_LENGTH) {
  103. scene_state->code_input[scene_state->code_length] = PinCodeArrowRight;
  104. scene_state->code_length++;
  105. }
  106. break;
  107. case InputKeyLeft:
  108. if(scene_state->code_length < MAX_CODE_LENGTH) {
  109. scene_state->code_input[scene_state->code_length] = PinCodeArrowLeft;
  110. scene_state->code_length++;
  111. }
  112. break;
  113. case InputKeyOk: {
  114. break;
  115. }
  116. case InputKeyBack:
  117. break;
  118. default:
  119. break;
  120. }
  121. } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) {
  122. CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
  123. &plugin_state->crypto_settings, &scene_state->code_input[0], scene_state->code_length);
  124. if(seed_result & CryptoSeedIVResultFlagSuccess &&
  125. seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
  126. totp_config_file_update_crypto_signatures(plugin_state);
  127. }
  128. if(totp_crypto_verify_key(&plugin_state->crypto_settings)) {
  129. totp_config_file_ensure_latest_encryption(
  130. plugin_state, &scene_state->code_input[0], scene_state->code_length);
  131. totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
  132. } else {
  133. memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
  134. memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
  135. scene_state->code_length = 0;
  136. DialogMessage* message = dialog_message_alloc();
  137. dialog_message_set_buttons(message, "Try again", NULL, NULL);
  138. dialog_message_set_header(
  139. message,
  140. "You entered\ninvalid PIN",
  141. SCREEN_WIDTH_CENTER - 25,
  142. SCREEN_HEIGHT_CENTER - 5,
  143. AlignCenter,
  144. AlignCenter);
  145. #if __has_include(<assets_icons.h>)
  146. dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22);
  147. #else
  148. dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
  149. #endif
  150. dialog_message_show(plugin_state->dialogs_app, message);
  151. dialog_message_free(message);
  152. }
  153. }
  154. return true;
  155. }
  156. void totp_scene_authenticate_deactivate(PluginState* plugin_state) {
  157. if(plugin_state->current_scene_state == NULL) return;
  158. free(plugin_state->current_scene_state);
  159. plugin_state->current_scene_state = NULL;
  160. }