booth 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE.md +1 -2
  4. data/README.md +37 -6
  5. data/app/assets/images/booth/browsers/README.md +1 -2
  6. data/app/assets/images/booth/browsers/chrome.svg +1 -1
  7. data/app/assets/images/booth/browsers/edge.svg +1 -1
  8. data/app/assets/images/booth/browsers/firefox.svg +1 -1
  9. data/app/assets/images/booth/browsers/opera.svg +1 -1
  10. data/app/assets/images/booth/browsers/safari.svg +1 -1
  11. data/app/assets/images/booth/fido/passkey_mark_a.svg +10 -0
  12. data/app/assets/images/booth/fido/passkey_mark_a_black.svg +32 -0
  13. data/app/assets/images/booth/fido/passkey_mark_a_reverse.svg +33 -0
  14. data/app/assets/images/booth/fido/passkey_mark_a_white.svg +32 -0
  15. data/app/assets/images/booth/fido/passkey_mark_b_black.svg +1 -0
  16. data/app/assets/images/booth/platforms/android.svg +1 -6
  17. data/app/assets/images/booth/platforms/apple.svg +1 -6
  18. data/app/assets/images/booth/platforms/linux.svg +1 -6
  19. data/app/assets/images/booth/platforms/windows.svg +1 -6
  20. data/app/assets/javascripts/booth/authentication.js +29 -0
  21. data/app/assets/javascripts/booth/authentication.js.map +1 -0
  22. data/app/assets/javascripts/booth/error.js +38 -0
  23. data/app/assets/javascripts/booth/error.js.map +1 -0
  24. data/app/assets/javascripts/booth/form.js +78 -0
  25. data/app/assets/javascripts/booth/form.js.map +1 -0
  26. data/app/assets/javascripts/booth/gui.js +53 -0
  27. data/app/assets/javascripts/booth/gui.js.map +1 -0
  28. data/app/assets/javascripts/booth/registration.js +29 -0
  29. data/app/assets/javascripts/booth/registration.js.map +1 -0
  30. data/app/assets/javascripts/booth/setup.js +14 -0
  31. data/app/assets/javascripts/booth/verification.js +49 -0
  32. data/app/assets/javascripts/booth/verification.js.map +1 -0
  33. data/app/assets/javascripts/declarations/authentication.d.ts +6 -0
  34. data/app/assets/javascripts/declarations/error.d.ts +36 -0
  35. data/app/assets/javascripts/declarations/form.d.ts +8 -0
  36. data/app/assets/javascripts/declarations/gui.d.ts +4 -0
  37. data/app/assets/javascripts/declarations/registration.d.ts +6 -0
  38. data/app/assets/javascripts/declarations/setup.d.ts +3 -0
  39. data/app/assets/javascripts/declarations/verification.d.ts +6 -0
  40. data/app/assets/javascripts/src/authentication.ts +41 -0
  41. data/app/assets/javascripts/src/error.ts +35 -0
  42. data/app/assets/javascripts/src/form.ts +90 -0
  43. data/app/assets/javascripts/src/gui.ts +59 -0
  44. data/app/assets/javascripts/src/registration.ts +44 -0
  45. data/app/assets/javascripts/src/verification.ts +61 -0
  46. data/app/assets/stylesheets/booth/booth.css +3 -0
  47. data/config/importmap.rb +11 -0
  48. data/config/locales/de.yml +14 -38
  49. data/config/locales/en.yml +17 -36
  50. data/data/combined_aaguid.json +1 -0
  51. data/lib/booth/adminland/credentials/create.rb +10 -12
  52. data/lib/booth/adminland/credentials/index.rb +31 -0
  53. data/lib/booth/adminland/onboardings/create.rb +24 -15
  54. data/lib/booth/adminland/onboardings/destroy.rb +8 -4
  55. data/lib/booth/adminland/onboardings/find.rb +52 -45
  56. data/lib/booth/adminland/onboardings/find_unconsumed.rb +61 -0
  57. data/lib/booth/adminland/onboardings/index.rb +6 -3
  58. data/lib/booth/adminland/periodic_cleanup.rb +7 -2
  59. data/lib/booth/adminland.rb +17 -18
  60. data/lib/booth/coercers/domain.rb +11 -0
  61. data/lib/booth/coercers/request.rb +51 -0
  62. data/lib/booth/coercers/scope.rb +11 -0
  63. data/lib/booth/comparisons/domain.rb +38 -0
  64. data/lib/booth/comparisons/scope.rb +38 -0
  65. data/lib/booth/concerns/action.rb +25 -13
  66. data/lib/booth/concerns/transition.rb +5 -2
  67. data/lib/booth/configuration.rb +14 -73
  68. data/lib/booth/configure.rb +3 -10
  69. data/lib/booth/{audits/register → core/audit}/completed_onboarding.rb +8 -6
  70. data/lib/booth/core/audit/credential_created.rb +24 -0
  71. data/lib/booth/core/audit/logout.rb +24 -0
  72. data/lib/booth/core/authenticators/confirm.rb +30 -0
  73. data/lib/booth/core/authenticators/step.rb +24 -0
  74. data/lib/booth/core/cooldowns/distance_of_time.rb +50 -0
  75. data/lib/booth/core/cooldowns/strategies/exponential.rb +88 -0
  76. data/lib/booth/core/cooldowns/strategies/global.rb +66 -0
  77. data/lib/booth/core/cooldowns/strategies/result.rb +27 -0
  78. data/lib/booth/core/credentials/create.rb +32 -0
  79. data/lib/booth/core/credentials/find_by_username.rb +63 -0
  80. data/lib/booth/core/credentials/index.rb +15 -0
  81. data/lib/booth/core/credentials/webauth_challenge.rb +37 -0
  82. data/lib/booth/core/geolocation.rb +25 -0
  83. data/lib/booth/core/onboardings/find.rb +92 -0
  84. data/lib/booth/core/onboardings/step.rb +19 -0
  85. data/lib/booth/core/remotes/get.rb +45 -0
  86. data/lib/booth/core/remotes/respond.rb +82 -0
  87. data/lib/booth/core/remotes/set_for_login.rb +31 -0
  88. data/lib/booth/core/sessions/create_and_login.rb +63 -0
  89. data/lib/booth/core/sessions/historical_locations.rb +22 -0
  90. data/lib/booth/core/sessions/index.rb +66 -0
  91. data/lib/booth/core/sessions/revoke.rb +59 -0
  92. data/lib/booth/core/sessions/revoke_all_others.rb +49 -0
  93. data/lib/booth/core/sessions/to_passport.rb +35 -0
  94. data/lib/booth/core/webauth/authentication_verification.rb +76 -0
  95. data/lib/booth/core/webauth/options_for_create.rb +56 -0
  96. data/lib/booth/core/webauth/options_for_get.rb +30 -0
  97. data/lib/booth/core/webauth/provider.rb +36 -0
  98. data/lib/booth/core/webauth/registration_verification.rb +100 -0
  99. data/lib/booth/credential.rb +35 -0
  100. data/lib/booth/engine.rb +15 -4
  101. data/lib/booth/errors.rb +2 -0
  102. data/lib/booth/hooks/after_fetch.rb +14 -6
  103. data/lib/booth/hooks/before_logout.rb +5 -3
  104. data/lib/booth/hooks/serialize_from_session.rb +13 -5
  105. data/lib/booth/hooks/serialize_into_session.rb +6 -3
  106. data/lib/booth/logging.rb +13 -42
  107. data/lib/booth/models/application_record.rb +3 -0
  108. data/lib/booth/models/audit.rb +10 -11
  109. data/lib/booth/models/authenticator.rb +6 -9
  110. data/lib/booth/models/credential.rb +17 -20
  111. data/lib/booth/models/onboarding.rb +16 -39
  112. data/lib/booth/models/{contest.rb → remote.rb} +13 -14
  113. data/lib/booth/models/remotes/scopes/recently_created.rb +26 -0
  114. data/lib/booth/models/remotes/scopes/recently_responded.rb +35 -0
  115. data/lib/booth/models/session.rb +15 -10
  116. data/lib/booth/models/user_agent.rb +2 -0
  117. data/lib/booth/request.rb +43 -22
  118. data/lib/booth/requests/agent.rb +3 -1
  119. data/lib/booth/requests/authentication.rb +15 -5
  120. data/lib/booth/requests/ip.rb +4 -2
  121. data/lib/booth/requests/return_path.rb +4 -2
  122. data/lib/booth/requests/session.rb +6 -4
  123. data/lib/booth/requests/storage.rb +5 -31
  124. data/lib/booth/requests/storages/login.rb +35 -29
  125. data/lib/booth/requests/storages/registration.rb +2 -0
  126. data/lib/booth/requests/storages/webauth.rb +3 -0
  127. data/lib/booth/requests/sudo.rb +6 -50
  128. data/lib/booth/routes/userland.rb +13 -59
  129. data/lib/booth/syntaxes/domain.rb +46 -0
  130. data/lib/booth/syntaxes/email.rb +11 -8
  131. data/lib/booth/syntaxes/ip.rb +6 -4
  132. data/lib/booth/syntaxes/remote_code.rb +60 -0
  133. data/lib/booth/syntaxes/scope.rb +7 -3
  134. data/lib/booth/syntaxes/secret_key.rb +8 -6
  135. data/lib/booth/syntaxes/username.rb +23 -10
  136. data/lib/booth/syntaxes/uuid.rb +3 -1
  137. data/lib/booth/test.rb +27 -22
  138. data/lib/booth/testing/incorporation_test_case.rb +29 -0
  139. data/lib/booth/testing/shortcuts.rb +77 -0
  140. data/lib/booth/testing/support/assert_all_partials_were_covered.rb +69 -0
  141. data/lib/booth/testing/support/assert_logged_in.rb +68 -0
  142. data/lib/booth/{test → testing}/support/assert_logged_out.rb +7 -4
  143. data/lib/booth/testing/support/assert_partial.rb +56 -0
  144. data/lib/booth/{test → testing}/support/force_login.rb +10 -4
  145. data/lib/booth/{test → testing}/support/get_session_value.rb +8 -6
  146. data/lib/booth/testing/support/scenario.rb +23 -0
  147. data/lib/booth/testing/support/shortcuts/create_and_onboard.rb +56 -0
  148. data/lib/booth/testing/support/shortcuts/login_with_passkey.rb +55 -0
  149. data/lib/booth/testing/support/shortcuts/register_new_passkey.rb +51 -0
  150. data/lib/booth/testing/support/soft_reset_session.rb +24 -0
  151. data/lib/booth/testing/support/virtual_authenticators/create.rb +34 -0
  152. data/lib/booth/testing/support/virtual_authenticators/destroy.rb +20 -0
  153. data/lib/booth/testing/support/virtual_authenticators/enable.rb +24 -0
  154. data/lib/booth/testing/support/virtual_authenticators/load.rb +38 -0
  155. data/lib/booth/testing/support/virtual_authenticators/manager.rb +124 -0
  156. data/lib/booth/testing/support/visit.rb +62 -0
  157. data/lib/booth/testing/userland/login_remotely.rb +100 -0
  158. data/lib/booth/testing/userland/onboarding_first_time.rb +81 -0
  159. data/lib/booth/testing/userland/onboarding_to_reset_passkeys.rb +129 -0
  160. data/lib/booth/testing/userland/registration_with_passkey.rb +93 -0
  161. data/lib/booth/testing/userland/registration_without_passkey.rb +101 -0
  162. data/lib/booth/testing/userland/sessions_manage_behavior.rb +68 -0
  163. data/lib/booth/testing/userland/sessions_revoke_all_others.rb +17 -0
  164. data/lib/booth/testing/userland/sessions_revoke_one.rb +17 -0
  165. data/lib/booth/testing/userland.rb +36 -0
  166. data/lib/booth/to_struct.rb +9 -2
  167. data/lib/booth/userland/extract_flash_messages.rb +10 -3
  168. data/lib/booth/userland/logins/create.rb +8 -6
  169. data/lib/booth/userland/logins/destroy.rb +23 -6
  170. data/lib/booth/userland/logins/new.rb +23 -25
  171. data/lib/booth/userland/logins/transitions/create/choose_username.rb +62 -27
  172. data/lib/booth/userland/logins/transitions/create/skip_remotes.rb +18 -14
  173. data/lib/booth/userland/logins/transitions/create/webauth_authentication_initiation.rb +54 -48
  174. data/lib/booth/userland/logins/transitions/create/webauth_authentication_verification.rb +62 -58
  175. data/lib/booth/userland/logins/transitions/new/already_logged_in.rb +4 -3
  176. data/lib/booth/userland/logins/transitions/new/fallible.rb +4 -0
  177. data/lib/booth/userland/logins/transitions/new/{mode_username_and_password.rb → missing_authenticators.rb} +5 -4
  178. data/lib/booth/userland/logins/transitions/new/mode_username_and_webauth.rb +6 -4
  179. data/lib/booth/userland/logins/transitions/new/no_username_chosen.rb +3 -1
  180. data/lib/booth/userland/logins/transitions/new/remote_session_available.rb +20 -13
  181. data/lib/booth/userland/logins/transitions/new/timed_out.rb +3 -1
  182. data/lib/booth/userland/onboardings/show.rb +65 -39
  183. data/lib/booth/userland/onboardings/update.rb +46 -38
  184. data/lib/booth/userland/registrations/create.rb +51 -20
  185. data/lib/booth/userland/registrations/new.rb +6 -7
  186. data/lib/booth/userland/remotes/show.rb +56 -0
  187. data/lib/booth/userland/{personal_contests → remotes}/update.rb +5 -3
  188. data/lib/booth/userland/sessions/destroy_one_or_other.rb +3 -16
  189. data/lib/booth/userland/sessions/index.rb +4 -2
  190. data/lib/booth/userland/sessions/show.rb +5 -6
  191. data/lib/booth/userland/sessions/transitions/destroy/enter_webauth.rb +8 -6
  192. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_initiation.rb +8 -6
  193. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_verification.rb +7 -5
  194. data/lib/booth/userland/sessions/transitions/show/enter_webauth.rb +8 -6
  195. data/lib/booth/userland/webauths/create.rb +20 -17
  196. data/lib/booth/userland/webauths/destroy.rb +6 -16
  197. data/lib/booth/userland/webauths/guards/sudo.rb +10 -5
  198. data/lib/booth/userland/webauths/index.rb +4 -2
  199. data/lib/booth/userland/webauths/new.rb +7 -22
  200. data/lib/booth/userland/webauths/sudo.rb +3 -1
  201. data/lib/booth/userland/webauths/transitions/create/authentication_initiation.rb +8 -11
  202. data/lib/booth/userland/webauths/transitions/create/authentication_verification.rb +11 -13
  203. data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +8 -5
  204. data/lib/booth/userland/webauths/transitions/create/registration_initiation.rb +15 -14
  205. data/lib/booth/userland/webauths/transitions/create/registration_verification.rb +34 -28
  206. data/lib/booth/userland/webauths/transitions/create/reset.rb +2 -0
  207. data/lib/booth/userland/webauths/transitions/new/step.rb +3 -1
  208. data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +5 -10
  209. data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +4 -2
  210. data/lib/booth/userland.rb +53 -109
  211. data/lib/booth/version.rb +3 -1
  212. data/lib/booth.rb +6 -236
  213. data/lib/generators/booth/migration/migration_generator.rb +2 -1
  214. data/lib/generators/booth/migration/templates/add_credential_to_users.erb +6 -4
  215. data/lib/generators/booth/migration/templates/create_booth_tables.erb +61 -72
  216. metadata +124 -571
  217. data/app/assets/config/booth_manifest.js +0 -15
  218. data/app/assets/images/booth/browsers/internet_explorer.svg +0 -1
  219. data/app/assets/javascripts/booth/all.js +0 -162
  220. data/app/assets/javascripts/booth/all.js.map +0 -1
  221. data/app/assets/javascripts/booth/booth.ts +0 -194
  222. data/app/assets/javascripts/booth/webauthn-json.ts +0 -99
  223. data/lib/booth/adminland/recoveries/consume.rb +0 -70
  224. data/lib/booth/audits/register/added_otp.rb +0 -22
  225. data/lib/booth/audits/register/changed_otp.rb +0 -22
  226. data/lib/booth/audits/register/correct_otp.rb +0 -42
  227. data/lib/booth/audits/register/correct_password.rb +0 -43
  228. data/lib/booth/audits/register/logout.rb +0 -22
  229. data/lib/booth/audits/register/requested_password_reset.rb +0 -22
  230. data/lib/booth/audits/register/wrong_otp.rb +0 -22
  231. data/lib/booth/audits/register/wrong_password.rb +0 -25
  232. data/lib/booth/authenticators/confirm.rb +0 -34
  233. data/lib/booth/authenticators/credential_mode_after_confirmation.rb +0 -25
  234. data/lib/booth/authenticators/step.rb +0 -19
  235. data/lib/booth/contests/get.rb +0 -36
  236. data/lib/booth/contests/respond.rb +0 -78
  237. data/lib/booth/contests/set_for_login.rb +0 -28
  238. data/lib/booth/cooldowns/distance_of_time.rb +0 -46
  239. data/lib/booth/cooldowns/otp.rb +0 -22
  240. data/lib/booth/cooldowns/password.rb +0 -44
  241. data/lib/booth/cooldowns/password_reset.rb +0 -24
  242. data/lib/booth/cooldowns/strategies/exponential.rb +0 -82
  243. data/lib/booth/cooldowns/strategies/global.rb +0 -62
  244. data/lib/booth/cooldowns/strategies/result.rb +0 -22
  245. data/lib/booth/credentials/create.rb +0 -28
  246. data/lib/booth/credentials/create_with_onboarding.rb +0 -26
  247. data/lib/booth/credentials/find_by_username.rb +0 -45
  248. data/lib/booth/credentials/mode.rb +0 -69
  249. data/lib/booth/credentials/modes/otp_addable.rb +0 -23
  250. data/lib/booth/credentials/modes/otp_changeable.rb +0 -23
  251. data/lib/booth/credentials/modes/otp_manageable.rb +0 -17
  252. data/lib/booth/credentials/modes/otp_removable.rb +0 -23
  253. data/lib/booth/credentials/modes/password_addable.rb +0 -29
  254. data/lib/booth/credentials/modes/password_changeable.rb +0 -31
  255. data/lib/booth/credentials/modes/password_manageable.rb +0 -17
  256. data/lib/booth/credentials/modes/password_removable.rb +0 -24
  257. data/lib/booth/credentials/modes/password_removal_requires_user_verifiable_webauth.rb +0 -16
  258. data/lib/booth/credentials/modes/webauth_addable.rb +0 -26
  259. data/lib/booth/credentials/modes/webauth_manageable.rb +0 -16
  260. data/lib/booth/credentials/modes/webauth_removable.rb +0 -25
  261. data/lib/booth/credentials/otp_authentication.rb +0 -59
  262. data/lib/booth/credentials/password_authentication.rb +0 -72
  263. data/lib/booth/credentials/webauth_challenge.rb +0 -28
  264. data/lib/booth/geolocation.rb +0 -20
  265. data/lib/booth/logger.rb +0 -41
  266. data/lib/booth/method_object.rb +0 -73
  267. data/lib/booth/mode.rb +0 -22
  268. data/lib/booth/models/concerns/modeable.rb +0 -50
  269. data/lib/booth/models/concerns/otpable.rb +0 -37
  270. data/lib/booth/models/concerns/passwordable.rb +0 -58
  271. data/lib/booth/models/contests/scopes/recently_created.rb +0 -23
  272. data/lib/booth/models/contests/scopes/recently_responded.rb +0 -32
  273. data/lib/booth/models/password_reset.rb +0 -41
  274. data/lib/booth/models/recovery.rb +0 -32
  275. data/lib/booth/models/registration.rb +0 -10
  276. data/lib/booth/modes/base.rb +0 -25
  277. data/lib/booth/modes/username_and_password.rb +0 -7
  278. data/lib/booth/modes/username_and_webauth.rb +0 -7
  279. data/lib/booth/modes/username_password_and_otp.rb +0 -7
  280. data/lib/booth/modes/username_password_and_webauth.rb +0 -7
  281. data/lib/booth/onboardings/find.rb +0 -35
  282. data/lib/booth/onboardings/propagate_to_credential.rb +0 -63
  283. data/lib/booth/onboardings/step.rb +0 -68
  284. data/lib/booth/password_resets/create.rb +0 -57
  285. data/lib/booth/password_resets/find.rb +0 -36
  286. data/lib/booth/password_resets/propagate_to_credential.rb +0 -36
  287. data/lib/booth/password_resets/step.rb +0 -18
  288. data/lib/booth/recoveries/create.rb +0 -45
  289. data/lib/booth/requests/storages/otp.rb +0 -54
  290. data/lib/booth/requests/storages/password.rb +0 -49
  291. data/lib/booth/requests/storages/password_reset.rb +0 -35
  292. data/lib/booth/requests/storages/recovery.rb +0 -35
  293. data/lib/booth/sessions/create_and_login.rb +0 -46
  294. data/lib/booth/sessions/historical_locations.rb +0 -18
  295. data/lib/booth/sessions/index.rb +0 -59
  296. data/lib/booth/sessions/revoke.rb +0 -51
  297. data/lib/booth/sessions/revoke_all_others.rb +0 -43
  298. data/lib/booth/sessions/to_passport.rb +0 -51
  299. data/lib/booth/syntaxes/contest_code.rb +0 -58
  300. data/lib/booth/syntaxes/otp.rb +0 -57
  301. data/lib/booth/syntaxes/scope_comparison.rb +0 -28
  302. data/lib/booth/test/helpers.rb +0 -63
  303. data/lib/booth/test/support/assert_all_partials_were_covered.rb +0 -63
  304. data/lib/booth/test/support/assert_logged_in.rb +0 -49
  305. data/lib/booth/test/support/assert_partial.rb +0 -29
  306. data/lib/booth/test/support/otp_code_from_session.rb +0 -30
  307. data/lib/booth/test/support/soft_reset_session.rb +0 -22
  308. data/lib/booth/test/userland/logins/missing_authenticators.rb +0 -72
  309. data/lib/booth/test/userland/logins/missing_onboarding.rb +0 -35
  310. data/lib/booth/test/userland/logins/username_and_password.rb +0 -40
  311. data/lib/booth/test/userland/logins/username_and_webauth.rb +0 -75
  312. data/lib/booth/test/userland/logins/username_password_and_otp.rb +0 -45
  313. data/lib/booth/test/userland/logins/username_password_and_webauth.rb +0 -86
  314. data/lib/booth/test/userland/onboardings/already_logged_in.rb +0 -64
  315. data/lib/booth/test/userland/onboardings/otp.rb +0 -63
  316. data/lib/booth/test/userland/onboardings/password.rb +0 -49
  317. data/lib/booth/test/userland/onboardings/timeout.rb +0 -47
  318. data/lib/booth/test/userland/otps/manage.rb +0 -86
  319. data/lib/booth/test/userland/password_resets/reset.rb +0 -102
  320. data/lib/booth/test/userland.rb +0 -38
  321. data/lib/booth/test/webauthn/disable.rb +0 -17
  322. data/lib/booth/test/webauthn/enable.rb +0 -19
  323. data/lib/booth/test/webauthn/virtual_authenticators/create.rb +0 -38
  324. data/lib/booth/test/webauthn/virtual_authenticators/destroy.rb +0 -20
  325. data/lib/booth/userland/logins/transitions/create/enter_otp.rb +0 -70
  326. data/lib/booth/userland/logins/transitions/create/verify_password.rb +0 -70
  327. data/lib/booth/userland/logins/transitions/new/mode_first_time.rb +0 -20
  328. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_otp.rb +0 -24
  329. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_webauth.rb +0 -24
  330. data/lib/booth/userland/onboardings/transitions/update/choose_mode.rb +0 -58
  331. data/lib/booth/userland/onboardings/transitions/update/choose_password.rb +0 -41
  332. data/lib/booth/userland/onboardings/transitions/update/choose_webauth_nickname.rb +0 -50
  333. data/lib/booth/userland/onboardings/transitions/update/confirm_otp.rb +0 -58
  334. data/lib/booth/userland/onboardings/transitions/update/confirm_password.rb +0 -49
  335. data/lib/booth/userland/onboardings/transitions/update/register_otp.rb +0 -31
  336. data/lib/booth/userland/onboardings/transitions/update/reset_otp.rb +0 -40
  337. data/lib/booth/userland/onboardings/transitions/update/reset_password.rb +0 -35
  338. data/lib/booth/userland/onboardings/transitions/update/reset_webauth.rb +0 -46
  339. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_initiation.rb +0 -40
  340. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_verification.rb +0 -59
  341. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_initiation.rb +0 -46
  342. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_verification.rb +0 -56
  343. data/lib/booth/userland/otps/destroy.rb +0 -42
  344. data/lib/booth/userland/otps/edit.rb +0 -72
  345. data/lib/booth/userland/otps/guards/manageable.rb +0 -21
  346. data/lib/booth/userland/otps/guards/sudo.rb +0 -23
  347. data/lib/booth/userland/otps/show.rb +0 -36
  348. data/lib/booth/userland/otps/sudo.rb +0 -51
  349. data/lib/booth/userland/otps/transitions/update/confirm.rb +0 -84
  350. data/lib/booth/userland/otps/transitions/update/register.rb +0 -40
  351. data/lib/booth/userland/otps/transitions/update/reset.rb +0 -31
  352. data/lib/booth/userland/otps/update.rb +0 -34
  353. data/lib/booth/userland/password_resets/create.rb +0 -73
  354. data/lib/booth/userland/password_resets/guards/logged_out.rb +0 -21
  355. data/lib/booth/userland/password_resets/new.rb +0 -57
  356. data/lib/booth/userland/password_resets/show.rb +0 -77
  357. data/lib/booth/userland/password_resets/transitions/update/choose_password.rb +0 -48
  358. data/lib/booth/userland/password_resets/transitions/update/confirm_password.rb +0 -54
  359. data/lib/booth/userland/password_resets/transitions/update/reset_password.rb +0 -29
  360. data/lib/booth/userland/password_resets/update.rb +0 -65
  361. data/lib/booth/userland/passwords/destroy.rb +0 -41
  362. data/lib/booth/userland/passwords/edit.rb +0 -54
  363. data/lib/booth/userland/passwords/guards/manageable.rb +0 -21
  364. data/lib/booth/userland/passwords/guards/removable.rb +0 -21
  365. data/lib/booth/userland/passwords/guards/sudo.rb +0 -21
  366. data/lib/booth/userland/passwords/remove.rb +0 -34
  367. data/lib/booth/userland/passwords/show.rb +0 -32
  368. data/lib/booth/userland/passwords/sudo.rb +0 -55
  369. data/lib/booth/userland/passwords/transitions/remove/step.rb +0 -27
  370. data/lib/booth/userland/passwords/transitions/update/choose_password.rb +0 -62
  371. data/lib/booth/userland/passwords/transitions/update/confirm_password.rb +0 -82
  372. data/lib/booth/userland/passwords/update.rb +0 -33
  373. data/lib/booth/userland/personal_contests/show.rb +0 -60
  374. data/lib/booth/userland/recoveries/create.rb +0 -48
  375. data/lib/booth/userland/recoveries/new.rb +0 -35
  376. data/lib/booth/userland/sessions/transitions/destroy/enter_password.rb +0 -50
  377. data/lib/booth/userland/sessions/transitions/destroy/verify_password.rb +0 -83
  378. data/lib/booth/userland/webauths/guards/manageable.rb +0 -21
  379. data/lib/booth/webauth/authentication_verification.rb +0 -68
  380. data/lib/booth/webauth/demand_user_verification.rb +0 -29
  381. data/lib/booth/webauth/options_for_create.rb +0 -46
  382. data/lib/booth/webauth/options_for_get.rb +0 -29
  383. data/lib/generators/booth/migration/templates/create_booth_mode_types.erb +0 -20
@@ -0,0 +1,41 @@
1
+ import * as Gui from 'booth/gui'
2
+ import { Verification } from 'booth/verification'
3
+ import { AuthenticationError } from 'booth/error'
4
+
5
+ // --------------------------------
6
+ // WebAuthn Authentication Ceremony
7
+ // --------------------------------
8
+
9
+ // Essentially a Login using an alreadyregistered authenticator.
10
+
11
+ export class Authentication {
12
+ private form: HTMLFormElement
13
+ private challengeData: any
14
+
15
+ constructor(form: HTMLFormElement, challengeData: any) {
16
+ Gui.clearErrors()
17
+ this.form = form
18
+ this.challengeData = challengeData
19
+ this.call()
20
+ }
21
+
22
+ private async call(): Promise<void> {
23
+ console.debug('WebAuthn Authentication - Step 1 - Sending challenge to Authenticator')
24
+
25
+ try {
26
+ const publicKey = PublicKeyCredential.parseRequestOptionsFromJSON(this.challengeData)
27
+ const response = await navigator.credentials.get({ publicKey })
28
+ if (!response) throw new Error('No credential created')
29
+ console.debug('WebAuthn Authentication - Step 2 - Received challenge response from Authenticator:')
30
+ console.debug(response)
31
+
32
+ new Verification(this.form, response)
33
+
34
+ } catch (error: unknown) {
35
+ console.error(`WebAuthn Authentication - Step 2 - FAILED`)
36
+ const registrationError = new AuthenticationError('Passkey Registration failed', error)
37
+ Gui.error(registrationError)
38
+ }
39
+ }
40
+ }
41
+
@@ -0,0 +1,35 @@
1
+ export class BoothError {
2
+ message: string;
3
+ object?: unknown;
4
+ name: string;
5
+
6
+ constructor(message: string, object?: unknown) {
7
+ this.message = message;
8
+ this.name = this.constructor.name;
9
+ this.object = object;
10
+ }
11
+ }
12
+
13
+ export class AuthenticationError extends BoothError { }
14
+ export class RegistrationError extends BoothError { }
15
+ export class VerificationRequestError extends BoothError { }
16
+ export class VerificationError extends BoothError { }
17
+ export class ServerResponseError extends BoothError { }
18
+ export class FormSubmissionError extends BoothError { }
19
+
20
+ export class FetchError extends BoothError { }
21
+ export class WebAuthnError extends BoothError { }
22
+ export class NetworkError extends BoothError { }
23
+
24
+ export const Booth = {
25
+ Error: BoothError,
26
+ FetchError,
27
+ WebAuthnError,
28
+ NetworkError,
29
+ AuthenticationError,
30
+ RegistrationError,
31
+ VerificationRequestError,
32
+ VerificationError,
33
+ ServerResponseError,
34
+ FormSubmissionError,
35
+ } as const;
@@ -0,0 +1,90 @@
1
+ import * as Gui from 'booth/gui'
2
+ import { Registration } from 'booth/registration'
3
+ import { Authentication } from 'booth/authentication'
4
+ import { ServerResponseError } from 'booth/error'
5
+ import { FormSubmissionError } from 'booth/error'
6
+
7
+ export class Form {
8
+ private form: HTMLFormElement
9
+
10
+ constructor(form: HTMLFormElement) {
11
+ this.form = form
12
+ }
13
+
14
+ setupRegistration() {
15
+ this.form.addEventListener('submit', async (event: Event) => {
16
+ console.debug('WebAuthn Registration - Step 1 - User clicked register new device button')
17
+ event.preventDefault()
18
+
19
+ console.debug('WebAuthn Registration - Step 2 - Client requests challenge from Relying Party')
20
+ this.submitAsynchronously((form, data) => {
21
+ console.debug('WebAuthn Registration - Step 3 - Client received challenge from Relying Party')
22
+ console.debug(data)
23
+ new Registration(form, data)
24
+ })
25
+ })
26
+
27
+ this.enableButtons()
28
+ console.debug("[Booth] Loaded Registration Form.")
29
+ }
30
+
31
+ setupAuthentication() {
32
+ this.form.addEventListener('submit', async (event: Event) => {
33
+ console.debug('WebAuthn Authentication - Step 1 - User clicked login')
34
+ event.preventDefault()
35
+
36
+ console.debug('WebAuthn Authentication - Step 2 - Client requests challenge from Relying Party')
37
+ this.submitAsynchronously((form, data) => {
38
+ console.debug('WebAuthn Authentication - Step 3 - Client received challenge from Relying Party:')
39
+ console.debug(data)
40
+ new Authentication(form, data)
41
+ })
42
+ })
43
+
44
+ this.enableButtons()
45
+ console.debug("[Booth] Loaded Authentication Form.")
46
+ }
47
+
48
+ private async submitAsynchronously(onSuccess: (form: HTMLFormElement, data: any) => void) {
49
+ Gui.clearErrors()
50
+ const tokenInput = this.form.querySelector(`input[type="hidden"][name="authenticity_token"]`) as HTMLInputElement
51
+
52
+ const headers = new Headers({
53
+ 'Accept': 'application/json',
54
+ 'X-CSRF-Token': tokenInput?.value,
55
+ })
56
+
57
+ try {
58
+ const response = await fetch(this.form.action, {
59
+ headers,
60
+ redirect: 'manual',
61
+ method: this.form.method.toUpperCase(),
62
+ body: new FormData(this.form),
63
+ })
64
+ if (response.status !== 201) throw new ServerResponseError(`Expected status 201, got ${response.status}`, response)
65
+
66
+ const data = await response.json()
67
+ onSuccess(this.form, data)
68
+
69
+ } catch (error) {
70
+ console.error(`Form submission failed`)
71
+ const formSubmissionError = new FormSubmissionError('Form submission failed', error)
72
+ Gui.error(formSubmissionError)
73
+ }
74
+ }
75
+
76
+ private enableButtons() {
77
+ if (!window.PublicKeyCredential) {
78
+ console.error("WebAuth not supported by this browser")
79
+
80
+ } else if (!window.isSecureContext) {
81
+ console.error("This page is no secure context. Please use HTTPS or the domain ending .localhost")
82
+
83
+ } else {
84
+ this.form.querySelectorAll<HTMLButtonElement>('button').forEach(button => {
85
+ button.removeAttribute('disabled')
86
+ console.debug(`Unlocked Booth Passkey Trigger ${button.id}`)
87
+ })
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,59 @@
1
+ import { BoothError } from 'booth/error'
2
+ import { ServerResponseError } from 'booth/error'
3
+
4
+ export function error(error: BoothError) {
5
+ if (error.object) console.error(error.object)
6
+
7
+ extractErrorMessage(error.object).then(message => {
8
+ document.querySelectorAll<HTMLFormElement>('.js-booth-error').forEach((el) => {
9
+ el.querySelectorAll<HTMLFormElement>('.js-booth-error__details').forEach((details) => {
10
+ details.textContent = error.message + ' - ' + message
11
+ })
12
+ el.classList.remove('is-invisible')
13
+ })
14
+ })
15
+ }
16
+
17
+ export function clearErrors() {
18
+ document.querySelectorAll<HTMLFormElement>('.js-booth-error').forEach((el) => {
19
+ el.classList.add('is-invisible')
20
+ el.querySelectorAll<HTMLFormElement>('.js-booth-error__details').forEach((details) => {
21
+ details.textContent = 'Unknown Error'
22
+ })
23
+ })
24
+ }
25
+
26
+ export function reloadSoon() {
27
+ const seconds = Math.floor(Math.random() * 3) + 5
28
+ setTimeout(() => {
29
+ console.debug('Reloading page...')
30
+ window.location.reload()
31
+ }, 1000 * seconds)
32
+ }
33
+
34
+ async function extractErrorMessage(object: unknown): Promise<string> {
35
+ if (object instanceof ServerResponseError) {
36
+ return extractErrorMessage(object.object)
37
+
38
+ } else if (object instanceof Response) {
39
+ if (object.type == 'opaqueredirect') {
40
+ return "Unexpected Redirect by the Server"
41
+ }
42
+
43
+ try {
44
+ const data = await object.json()
45
+
46
+ return data.public_message ?? JSON.stringify(data)
47
+ } catch {
48
+ return String(object.status)
49
+ }
50
+
51
+ } else if (object instanceof Error) {
52
+ if (object.name === 'NotAllowedError') {
53
+ return 'Authentication was cancelled.'
54
+ }
55
+ return `${object.name} - ${object.message}`
56
+
57
+ }
58
+ return String(object)
59
+ }
@@ -0,0 +1,44 @@
1
+ import * as Gui from 'booth/gui'
2
+ import { Verification } from 'booth/verification'
3
+ import { RegistrationError } from 'booth/error'
4
+
5
+ // ------------------------------
6
+ // WebAuthn Registration Ceremony
7
+ // ------------------------------
8
+
9
+ // Assuming a user has already created an account with the online service,
10
+ // the user registers one or more authenticators against that identity.
11
+
12
+ export class Registration {
13
+ private form: HTMLFormElement
14
+ private challengeData: any
15
+
16
+ constructor(form: HTMLFormElement, challengeData: any) {
17
+ Gui.clearErrors()
18
+ this.form = form
19
+ this.challengeData = challengeData
20
+ this.call()
21
+ }
22
+
23
+ private async call(): Promise<void> {
24
+ console.debug('WebAuthn Registration - Step 4 - Sending challenge to Authenticator')
25
+
26
+ try {
27
+ const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(this.challengeData)
28
+ const response = await navigator.credentials.create({ publicKey })
29
+ if (!response) throw new Error('No credential created')
30
+
31
+ console.debug('WebAuthn Registration - Step 5 - Received challenge response from Authenticator')
32
+ console.debug(response)
33
+
34
+ new Verification(this.form, response)
35
+
36
+ } catch (error: unknown) {
37
+ // TODO: Better UI message when `InvalidStateError` happens (duplicate device).
38
+ // And maybe also a dedicated message for `AbortError` (user cancelled).
39
+ console.warn(`WebAuthn Registration - Step 4 - FAILED`)
40
+ const registrationError = new RegistrationError('Passkey Registration failed', error)
41
+ Gui.error(registrationError)
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,61 @@
1
+ import * as Gui from 'booth/gui'
2
+ import { VerificationRequestError, ServerResponseError } from 'booth/error'
3
+
4
+ export class Verification {
5
+ private form: HTMLFormElement
6
+ private handshake: any
7
+
8
+ public constructor(form: HTMLFormElement, handshake: any) {
9
+ Gui.clearErrors()
10
+ this.form = form
11
+ this.handshake = handshake
12
+ this.call()
13
+ }
14
+
15
+ private call() {
16
+ const methodInput = this.form.querySelector(`input[type="hidden"][name="_method"]`) as HTMLInputElement
17
+ const formData = new FormData(this.form)
18
+ const formDataObj = Object.fromEntries(formData)
19
+
20
+ const body = JSON.stringify({
21
+ ...formDataObj,
22
+ handshake: this.handshake,
23
+ })
24
+
25
+ const options: RequestInit = {
26
+ body: body,
27
+ method: methodInput?.value?.toUpperCase() || 'POST',
28
+ credentials: 'same-origin',
29
+ redirect: 'manual',
30
+ headers: {
31
+ 'Content-type': 'application/json',
32
+ 'Accept': 'application/json',
33
+ }
34
+ }
35
+
36
+ console.debug('WebAuthn Verification - Sending signed challenge to Relying Party')
37
+ console.debug(options)
38
+
39
+ fetch(this.form.action, options)
40
+ .then((response) => {
41
+
42
+ // Conventionally the server is programmed such that it returns 201 on successful WebAuth verification.
43
+ // That makes it easier to detect a mistake (most other server endpoints will usually respond with 200).
44
+ if (response.status == 201) {
45
+ console.debug(`WebAuthn Verification Phase - SUCCESS - ${response.statusText}`)
46
+ console.info(`Reloading page with a GET request: ${window.location.href}`)
47
+ window.location.href = window.location.href
48
+
49
+ } else {
50
+ console.warn(`WebAuthn Verification Phase - FAILED`)
51
+ throw new ServerResponseError('Server did not respond with 201', response)
52
+ }
53
+
54
+ }).catch((error: unknown) => {
55
+ console.warn(error)
56
+ console.warn(`WebAuthn Verification - FAILED`)
57
+ const wrappedError = new VerificationRequestError('Passkey Verification Request failed', error)
58
+ Gui.error(wrappedError)
59
+ })
60
+ }
61
+ }
@@ -0,0 +1,3 @@
1
+ .js-booth-error.is-invisible {
2
+ display: none;
3
+ }
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ pin 'booth', to: 'booth/setup.js'
4
+
5
+ pin 'booth/authentication', to: 'booth/authentication.js'
6
+ pin 'booth/error', to: 'booth/error.js'
7
+ pin 'booth/form', to: 'booth/form.js'
8
+ pin 'booth/gui', to: 'booth/gui.js'
9
+ pin 'booth/registration', to: 'booth/registration.js'
10
+ pin 'booth/setup', to: 'booth/setup.js'
11
+ pin 'booth/verification', to: 'booth/verification.js'
@@ -3,64 +3,42 @@ de:
3
3
  activerecord:
4
4
  attributes:
5
5
  booth/models/onboarding:
6
- password: Passwort
7
- password_confirmation: Passwort
8
6
  authenticator_nickname: Gerätename
9
- errors:
10
- messages:
11
- not_pwned: ist unsicher, weil es in %{count} Datenlecks veröffentlicht wurde.
12
7
 
13
8
  booth:
9
+ administratively_blocked: Dieser Benutzer wurde gesperrt. Bitte kontaktieren Sie unseren Kundenservice.
14
10
  all_other_sessions_revoked: All other devices except this one have been logged out.
15
- already_responded_to_contest: You have already responded to this contest.
11
+ already_responded_to_remote: You have already responded to this remote.
16
12
  attempt_was_ignored: Dieser Versuch wurde ignoriert.
17
13
  attempts_left: You may try %{attempts_left} more times.
18
14
  authenticator_not_found: Could not find that hardware key.
19
15
  authenticator_removal_failed: Could not delete that hardware key.
20
- blank_contest_code: You did not enter a code.
21
16
  blank_email: Please provide an email address.
22
17
  blank_nickname: Please provide a name for your device.
23
- blank_otp: Bitte gib den Einmalcode ein, den dir deine Authenticator App anzeigt.
24
- blank_password: Bitte gib dein Passwort ein.
18
+ blank_remote_code: You did not enter a code.
25
19
  blank_secret_key: The provided secret key is empty. Is the URL correct?
26
20
  blank_username: Trage bitte deinen Benutzernamen ein.
27
- contest_response_accepted: You entered the correct code. You have now been logged in on the other device.
28
- contest_timed_out: You had %{lifespan_minutes} minutes to enter the response code, but it took too long. Please start again.
21
+ domain_mismatch: Dieser Benutzername kann sich nicht hier einloggen.
29
22
  email_too_long: The provided email is too long. It must be less at most %{maximum} characters long.
30
23
  email_too_short: The provided email is too short. It should be at least %{minimum} characters long.
31
24
  incompatible_webauth_device: Sorry, this device cannot be used. Please try another webauth device.
32
- invalid_contest_code_format: Der Code darf nur aus Zahlen bestehen.
25
+ invalid_domain: Die Domain "%{domain}" ist keine gültige Domain.
33
26
  invalid_email_characters: The provided email address contains invalid characters.
34
27
  invalid_email_format: The provided email address does not look valid.
35
- invalid_otp_format: Der Einmalcode darf nur aus Zahlen bestehen.
28
+ invalid_remote_code_format: Der Code darf nur aus Zahlen bestehen.
36
29
  invalid_secret_key_format: The provided secret key contains invalid characters. It should be from the Base58 alphabet.
37
- invalid_username_format: Der eingegebene Benutzername enthält ungültige Zeichen.
30
+ invalid_username_format: Der eingegebene Benutzername enthält ungültige Zeichen. Nur Buchstaben und Zahlen sind erlaubt.
38
31
  last_attempt: This is your last attempt and you will have to contact customer service if you fail.
39
- logged_in_user_cannot_reset_password: You are currently logged in. If you forgot your password, try another browser or logout first.
40
32
  login_timeout: Du hattest %{lifespan_minutes} Minuten um den Login abzuschließen, es hat aber länger gedauert. Bitte beginne erneut.
41
33
  missing_secret_key: Missing the secret key parameter. Is the URL correct?
42
- mode_username_and_password_description: Benutzername und Passwort. Kann leicht gestohlen werden.
43
- mode_username_and_password_title: Passwort (unsicher)
44
34
  mode_username_and_webauth_description: Auch bekannt als WebAuthentication (WebAuthn), FIDO2, CTAP2, Apple Passkey (Touch ID, Face ID).
45
35
  mode_username_and_webauth_title: Hardwareschlüssel (empfohlen)
46
- mode_username_password_and_otp_description: Wenn kein kompatibler Hardwareschlüssel zur Hand ist.
47
- mode_username_password_and_otp_title: Passwort und Einmalpasswort
48
- mode_username_password_and_webauth_description: Zusätzlich zum Hardwareschlüssel muss jedesmal auch das Passwort eingegeben werden.
49
- mode_username_password_and_webauth_title: Passwort und Hardwareschlüssel (am sichersten)
50
- otp_removed: You successfully removed your OTP configuration.
51
- otp_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current OTP again.
52
- otp_unavailable: You can't use OTP at this time.
53
- password_changed: You successfully changed your password.
54
- password_removed: You successfully removed your password.
55
- password_reset_needs_username: To reset your password, please provide a username first.
56
- password_reset_not_available: This username cannot reset the password. Please contact support.
57
- password_successfully_reset: Your new password has been saved.
58
- password_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current password again.
59
- password_unavailable: You can't use a password at this time.
60
- passwordless_cannot_change_password: You cannot change your password because you don't have one.
36
+ onboarding_timeout: Sie hatten %{lifespan_hours} Stunden to access this onboarding link, but it took too long.
61
37
  permanently_blocked: You failed too many times for this account. Please contact customer service.
38
+ remote_login_path: fernlogin
39
+ remote_response_accepted: You entered the correct code. You have now been logged in on the other device.
40
+ remote_timed_out: You had %{lifespan_minutes} minutes to enter the response code, but it took too long. Please start again.
62
41
  session_revoked: Das Gerät mit der IP %{ip} wurde erfolgreich ausgeloggt.
63
- short_password: Das kann nicht dein Passwort sein, weil es zu kurz ist. Es muss aus mindestens %{minlength} Zeichen bestehen.
64
42
  some_authenticator_removed: Hardware key successfully deleted.
65
43
  successfully_logged_out: Du hast dich erfolgreich ausgeloggt.
66
44
  try_again_cooldown: Du kannst es in %{distance_of_time_until_cooldown} erneut probieren.
@@ -70,15 +48,13 @@ de:
70
48
  unknown_username: Dieser Benutzername existiert nicht.
71
49
  unknown_webauth_device: Sorry, We don't recognize that device. Have you registered it before?
72
50
  username_already_exists: This username already exists. Try to login instead?
51
+ username_must_start_with_letter: Der Benutzername muss mit einem Buchstaben beginnen.
73
52
  username_too_long: The provided username is too long. It must be less at most %{maximum} characters long.
74
53
  username_too_short: The provided username is too short. It should be at least %{minimum} characters long.
75
54
  webauth_irremovable: You cannot remove any of your hardware keys.
76
55
  webauth_missing_authenticators: You cannot login using webauth, because we don't know any of your hardware keys.
77
- webauth_removed: Hardware keys successfully deleted. Now you log in only with your password.
56
+ webauth_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current Passkey again.
78
57
  webauth_unavailable: You can't use WebAuthn at this time.
79
- wrong_contest_code_length: The code you entered was not %{digits} digits long.
80
- wrong_otp_length: Der Einmalcode muss aus %{digits} Zahlen bestehen.
81
- wrong_otp: Dieser Einmalcode ist falsch, vielleicht ist er schon abgelaufen.
82
- wrong_password: Das war nicht das richtige Passwort.
58
+ wrong_remote_code_length: The code you entered was not %{digits} digits long.
83
59
  wrong_response_code: This was not the code that is currently shown on the login page on the other device.
84
60
  wrong_secret_key_length: The provided secret key does not have the correct length. It should be 30 characters long.
@@ -1,61 +1,44 @@
1
1
  en:
2
2
 
3
3
  activerecord:
4
- errors:
5
- messages:
6
- not_pwned: is isecure, because it has been published in %{count} data leaks.
4
+ attributes:
5
+ booth/models/onboarding:
6
+ authenticator_nickname: Device Name
7
7
 
8
8
  booth:
9
+ administratively_blocked: This Account is blocked. Please contact customer service.
9
10
  all_other_sessions_revoked: All other devices except this one have been logged out.
10
- already_responded_to_contest: You have already responded to this contest.
11
+ already_responded_to_remote: You have already responded to this remote.
11
12
  attempt_was_ignored: This attempt has been ignored.
12
13
  attempts_left: You may try %{attempts_left} more times.
13
14
  authenticator_not_found: Could not find that hardware key.
14
15
  authenticator_removal_failed: Could not delete that hardware key.
15
- blank_contest_code: You did not enter a code.
16
16
  blank_email: Please provide an email address.
17
17
  blank_nickname: Please provide a name for your device.
18
- blank_otp: Please provide the one-time code your authenticator app is showing you.
19
- blank_password: Please provide a password.
18
+ blank_remote_code: You did not enter a code.
20
19
  blank_secret_key: The provided secret key is empty. Is the URL correct?
21
20
  blank_username: Please provide a username.
22
- contest_response_accepted: You entered the correct code. You have now been logged in on the other device.
23
- contest_timed_out: You had %{lifespan_minutes} minutes to enter the response code, but it took too long. Please start again.
21
+ domain_mismatch: This username cannot log in here.
24
22
  email_too_long: The provided email is too long. It must be less at most %{maximum} characters long.
25
23
  email_too_short: The provided email is too short. It should be at least %{minimum} characters long.
26
24
  incompatible_webauth_device: Sorry, this device cannot be used. Please try another webauth device.
27
- invalid_contest_code_format: The code may only consist of digits.
25
+ invalid_domain: The Domain "%{domain}" is not a valid domain name.
28
26
  invalid_email_characters: The provided email address contains invalid characters.
29
27
  invalid_email_format: The provided email address does not look valid.
30
- invalid_otp_format: The one-time may only consist of digits.
28
+ invalid_remote_code_format: The code may only consist of digits.
31
29
  invalid_secret_key_format: The provided secret key contains invalid characters. It should be from the Base58 alphabet.
32
- invalid_username_format: The provided username contains invalid characters.
30
+ invalid_username_format: The provided username contains invalid characters. Only letters and numbers are allowed.
33
31
  last_attempt: This is your last attempt and you will have to contact customer service if you fail.
34
- logged_in_user_cannot_reset_password: You are currently logged in. If you forgot your password, try another browser or logout first.
35
32
  login_timeout: You had %{lifespan_minutes} minutes to complete the login, but it took too long. Please start again.
36
33
  missing_secret_key: Missing the secret key parameter. Is the URL correct?
37
- mode_username_and_password_description: Username and password. Can easily be stolen.
38
- mode_username_and_password_title: Password (insecure)
39
34
  mode_username_and_webauth_description: Also known as WebAuthentication (WebAuthn), FIDO2, CTAP2, Apple Passkey (Touch ID, Face ID).
40
35
  mode_username_and_webauth_title: Hardware key (recommended)
41
- mode_username_password_and_otp_description: Use this if you don't have a hardware key.
42
- mode_username_password_and_otp_title: Password and one-time-password.
43
- mode_username_password_and_webauth_description: Additionally to your hardware key, you will have to enter your password. So nobody with your hardware key can just log in.
44
- mode_username_password_and_webauth_title: Password and hardware key (most secure)
45
- otp_removed: You successfully removed your OTP configuration.
46
- otp_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current OTP again.
47
- otp_unavailable: You can't use OTP at this time.
48
- password_changed: You successfully changed your password.
49
- password_removed: You successfully removed your password.
50
- password_reset_needs_username: To reset your password, please provide a username first.
51
- password_reset_not_available: This username cannot reset the password. Please contact support.
52
- password_successfully_reset: Your new password has been saved.
53
- password_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current password again.
54
- password_unavailable: You can't use a password at this time.
55
- passwordless_cannot_change_password: You cannot change your password because you don't have one.
36
+ onboarding_timeout: You had %{lifespan_hours} hours to access this onboarding link, but it took too long.
56
37
  permanently_blocked: You failed too many times for this account. Please contact customer service.
38
+ remote_login_path: remote
39
+ remote_response_accepted: You entered the correct code. You have now been logged in on the other device.
40
+ remote_timed_out: You had %{lifespan_minutes} minutes to enter the response code, but it took too long. Please start again.
57
41
  session_revoked: The logged in device with the IP %{ip} has successfully been logged out.
58
- short_password: That cannot be the password, because it was too short. It must be at least %{minlength} characters long.
59
42
  some_authenticator_removed: Hardware key successfully deleted.
60
43
  successfully_logged_out: Logout successful.
61
44
  try_again_cooldown: You may try again in %{distance_of_time_until_cooldown}.
@@ -65,15 +48,13 @@ en:
65
48
  unknown_username: We don't know that username.
66
49
  unknown_webauth_device: Sorry, We don't recognize that device. Have you registered it before?
67
50
  username_already_exists: This username already exists. Try to login instead?
51
+ username_must_start_with_letter: The provided username does not start with a letter (a-z).
68
52
  username_too_long: The provided username is too long. It must be less at most %{maximum} characters long.
69
53
  username_too_short: The provided username is too short. It should be at least %{minimum} characters long.
70
54
  webauth_irremovable: You cannot remove any of your hardware keys.
71
55
  webauth_missing_authenticators: You cannot login using webauth, because we don't know any of your hardware keys.
72
- webauth_removed: Hardware keys successfully deleted. Now you log in only with your password.
56
+ webauth_sudo_timeout: You had %{lifespan_minutes} minutes to perform this action, but it took too long. Please start again by providing your current Passkey again.
73
57
  webauth_unavailable: You can't use WebAuthn at this time.
74
- wrong_contest_code_length: The code you entered was not %{digits} digits long.
75
- wrong_otp_length: The one-time code must be %{digits} digits long.
76
- wrong_otp: The one-time code is wrong, maybe it already expired.
77
- wrong_password: Wrong password.
58
+ wrong_remote_code_length: The code you entered was not %{digits} digits long.
78
59
  wrong_response_code: This was not the code that is currently shown on the login page on the other device.
79
60
  wrong_secret_key_length: The provided secret key does not have the correct length. It should be 30 characters long.