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
@@ -1,36 +0,0 @@
1
- module Booth
2
- module PasswordResets
3
- class Find
4
- include ::Booth::Logging
5
- include ::Booth::MethodObject
6
-
7
- option :secret_key
8
-
9
- def call
10
- do_check_secret_key_syntax
11
- .on_success { do_find_password_reset }
12
- end
13
-
14
- private
15
-
16
- def do_check_secret_key_syntax
17
- ::Booth::Syntaxes::SecretKey.call(secret_key)
18
- end
19
-
20
- def do_find_password_reset
21
- debug { "Looking for PasswordReset with secret key #{secret_key.inspect}" }
22
- @password_reset = ::Booth::Models::PasswordReset.find_by(secret_key:)
23
-
24
- if @password_reset
25
- debug { "Found PasswordReset with ID #{@password_reset.id.inspect}" }
26
- @password_reset.update! accessed_at: Time.current if @password_reset.accessed_at.blank?
27
- return Tron.success(:found_password_reset, password_reset: @password_reset)
28
- end
29
-
30
- message = "Could not find userland PasswordReset with secret key #{secret_key.inspect}"
31
- debug { message }
32
- Tron.failure :password_reset_not_found, public_message: I18n.t('booth.unknown_secret_key')
33
- end
34
- end
35
- end
36
- end
@@ -1,36 +0,0 @@
1
- module Booth
2
- module PasswordResets
3
- class PropagateToCredential
4
- include ::Booth::Logging
5
- include ::Booth::MethodObject
6
-
7
- param :password_reset
8
-
9
- def call
10
- debug { 'Propagating PasswordReset to Credential...' }
11
- raise "Expected PasswordReset to be valid: #{password_reset.errors.to_a.to_sentence}" if password_reset.invalid?
12
-
13
- password_reset.transaction do
14
- update_credential!
15
- invalidate_password_resets!
16
- finalize_password_reset!
17
- end
18
- end
19
-
20
- private
21
-
22
- def update_credential!
23
- password_reset.credential.update! password_digest: password_reset.password_digest
24
- end
25
-
26
- def invalidate_password_resets!
27
- password_reset.other_password_resets_of_this_credential
28
- .update_all(revoked_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
29
- end
30
-
31
- def finalize_password_reset!
32
- password_reset.update! propagated_at: Time.current
33
- end
34
- end
35
- end
36
- end
@@ -1,18 +0,0 @@
1
- module Booth
2
- module PasswordResets
3
- class Step
4
- include ::Booth::MethodObject
5
-
6
- param :password_reset
7
-
8
- def call
9
- return :completed if password_reset.completed?
10
- return :revoked if password_reset.revoked?
11
- return :timed_out unless password_reset.recently_created?
12
- return :confirm_password if password_reset.password_chosen_at.present?
13
-
14
- :choose_password
15
- end
16
- end
17
- end
18
- end
@@ -1,45 +0,0 @@
1
- module Booth
2
- module Recoveries
3
- class Create
4
- include ::Booth::Logging
5
- include ::Booth::MethodObject
6
-
7
- option :scope
8
- option :email
9
- option :ip
10
-
11
- def call
12
- do_check_cooldown
13
- .on_success { do_check_email_syntax }
14
- .on_success { do_create_recovery }
15
- end
16
-
17
- private
18
-
19
- def do_check_cooldown
20
- # TODO: Check recovery cooldown of email in the table `booth_recoveries`.
21
- # Respect consumed_at and revoked_at and created_at and creator_ip and email.
22
- Tron.success :username_rate_limit_ok_dummy
23
- end
24
-
25
- def do_check_email_syntax
26
- check = ::Booth::Syntaxes::Email.call(email)
27
-
28
- check.on_success do
29
- @email_address = check.normalized_email
30
- end
31
-
32
- check
33
- end
34
-
35
- def do_create_recovery
36
- recovery = ::Booth::Models::Recovery.create! scope: scope,
37
- email: email,
38
- creator_ip: ip
39
-
40
- Tron.success :applicable_for_recovery, email: recovery.email,
41
- recovery_id: recovery.id
42
- end
43
- end
44
- end
45
- end
@@ -1,54 +0,0 @@
1
- module Booth
2
- module Requests
3
- module Storages
4
- class Otp
5
- include ::Booth::Logging
6
-
7
- delegate :reset, :timed_out?, :lifespan, :seconds_until_auto_reset, to: :session
8
-
9
- def initialize(session:)
10
- @session = session
11
- end
12
-
13
- # -------
14
- # Getters
15
- # -------
16
-
17
- def secret_key
18
- session[:secret_key]
19
- end
20
-
21
- def secret_key_has_been_seen?
22
- !!session[:secret_key_has_been_seen]
23
- end
24
-
25
- def secret_key_recently_changed?
26
- !!session[:secret_key_recently_changed]
27
- end
28
-
29
- # -------
30
- # Setters
31
- # -------
32
-
33
- def generate_secret_key!
34
- debug { 'Generating secret OTP key for registration' }
35
- session[:secret_key] = ::Booth::Models::Credential.otp_random_secret
36
- end
37
-
38
- def secret_key_has_been_seen!
39
- debug { 'Remembering that the secret OTP key has been registered' }
40
- session[:secret_key_has_been_seen] = true
41
- end
42
-
43
- def secret_key_recently_changed!
44
- reset
45
- session[:secret_key_recently_changed] = true
46
- end
47
-
48
- private
49
-
50
- attr_reader :session
51
- end
52
- end
53
- end
54
- end
@@ -1,49 +0,0 @@
1
- module Booth
2
- module Requests
3
- module Storages
4
- class Password
5
- include ::Booth::Logging
6
-
7
- delegate :reset, :timed_out?, :lifespan, :seconds_until_auto_reset, to: :session
8
-
9
- def initialize(session:)
10
- @session = session
11
- end
12
-
13
- # -------
14
- # Getters
15
- # -------
16
-
17
- def password_digest
18
- session[:password_digest]
19
- end
20
-
21
- # To show a reminder for the user to logout other devices after password change.
22
- # This value either times out or is deleted at read-confirmation by the user.
23
- def password_recently_changed?
24
- !!session[:password_recently_changed]
25
- end
26
-
27
- # -------
28
- # Setters
29
- # -------
30
-
31
- def password_digest=(new_password_digest)
32
- debug { 'Remembering new password digest' }
33
- session[:password_digest] = new_password_digest
34
- end
35
-
36
- def password_recently_changed!
37
- debug { 'Remembering that the password was recently changed' }
38
- session[:password_recently_changed] = true
39
- end
40
-
41
- private
42
-
43
- attr_reader :session
44
-
45
- delegate :scope, to: :session, private: true
46
- end
47
- end
48
- end
49
- end
@@ -1,35 +0,0 @@
1
- module Booth
2
- module Requests
3
- module Storages
4
- class PasswordReset
5
- include ::Booth::Logging
6
-
7
- delegate :reset, :timed_out?, :lifespan, :seconds_until_auto_reset, to: :session
8
-
9
- def initialize(session:)
10
- @session = session
11
- end
12
-
13
- # -------
14
- # Getters
15
- # -------
16
-
17
- def email
18
- session[:email]
19
- end
20
-
21
- # -------
22
- # Setters
23
- # -------
24
-
25
- def email=(new_email)
26
- session[:email] = new_email
27
- end
28
-
29
- private
30
-
31
- attr_reader :session
32
- end
33
- end
34
- end
35
- end
@@ -1,35 +0,0 @@
1
- module Booth
2
- module Requests
3
- module Storages
4
- class Recovery
5
- include ::Booth::Logging
6
-
7
- delegate :reset, :timed_out?, :lifespan, :seconds_until_auto_reset, to: :session
8
-
9
- def initialize(session:)
10
- @session = session
11
- end
12
-
13
- # -------
14
- # Getters
15
- # -------
16
-
17
- def email
18
- session[:email]
19
- end
20
-
21
- # -------
22
- # Setters
23
- # -------
24
-
25
- def email=(new_email)
26
- session[:email] = new_email
27
- end
28
-
29
- private
30
-
31
- attr_reader :session
32
- end
33
- end
34
- end
35
- end
@@ -1,46 +0,0 @@
1
- module Booth
2
- module Sessions
3
- class CreateAndLogin
4
- include ::Booth::MethodObject
5
- include ::Booth::Logging
6
-
7
- option :credential
8
- option :request, ::Booth::Request
9
-
10
- def call
11
- if request.scope != credential.scope.to_sym
12
- debug { "Request has scope #{request.scope.inspect} but Credential has #{credential.scope.to_sym.inspect}" }
13
- raise 'Not performing login because something in your setup is wrong.'
14
- end
15
-
16
- request.authentication
17
- .login(session: create_session)
18
-
19
- # Consume everything that led up to this authentication to avoid re-authentication.
20
- # If we don't reset the cookie here, the "remote login flow" could log you right back in.
21
- login_storage.reset
22
- registration_storage.reset
23
-
24
- Tron.success :session_created_and_logged_in, return_path: request.return_path
25
- end
26
-
27
- private
28
-
29
- def create_session
30
- debug { "Creating new Session for credential ID #{credential.id}" }
31
-
32
- ::Booth::Models::Session.create! credential:,
33
- agent: request.agent,
34
- most_recent_ip: request.ip
35
- end
36
-
37
- def login_storage
38
- request.storage.login
39
- end
40
-
41
- def registration_storage
42
- request.storage.registration
43
- end
44
- end
45
- end
46
- end
@@ -1,18 +0,0 @@
1
- module Booth
2
- module Sessions
3
- class HistoricalLocations
4
- include ::Booth::MethodObject
5
-
6
- param :session
7
-
8
- # TODO: Show IPs for cities that are different from the most recent IP.
9
- def call
10
- return if historical_locations.values.blank?
11
-
12
- historical_locations.values.reject { _1 == location }.uniq.sort.join(', ').presence
13
- end
14
-
15
- delegate :location, :historical_locations, to: :session, private: true
16
- end
17
- end
18
- end
@@ -1,59 +0,0 @@
1
- module Booth
2
- module Sessions
3
- class Index
4
- include ::Booth::MethodObject
5
-
6
- option :credential_id
7
- option :current_session_id
8
-
9
- def call
10
- # Booth currently doesn't support pagination.
11
- # To avoid an attacking vector that could bring our database down,
12
- # we simply pull the handbrake when trying to fetch too many sessions.
13
- # Nobody should have that many active concurrent sessions.
14
- raise "Too many sessions for Credential ID #{credential_id}" if base_scope.count > max_allowed_sessions
15
-
16
- base_scope.map do |session|
17
- ::Booth::ToStruct.call(exposed_attributes(session))
18
- end
19
- end
20
-
21
- private
22
-
23
- def exposed_attributes(session)
24
- result = { is_current: current_session_id == session.id }
25
-
26
- exposed_attribute_names.each do |attribute|
27
- result[attribute] = session.public_send(attribute)
28
- end
29
-
30
- result
31
- end
32
-
33
- def exposed_attribute_names
34
- %i[id
35
- activity_at
36
- created_at
37
- agent
38
- most_recent_ip
39
- historical_ips
40
- location
41
- historical_location_names
42
- browser_name
43
- platform_name
44
- browser_image_path
45
- platform_image_path]
46
- end
47
-
48
- def base_scope
49
- ::Booth::Models::Session.active_scope
50
- .sorted_scope
51
- .owned_by_scope(credential_id:)
52
- end
53
-
54
- def max_allowed_sessions
55
- 500
56
- end
57
- end
58
- end
59
- end
@@ -1,51 +0,0 @@
1
- module Booth
2
- module Sessions
3
- class Revoke
4
- include ::Booth::MethodObject
5
- include ::Booth::Logging
6
-
7
- option :credential_id
8
- option :session_id
9
-
10
- def call
11
- do_check_id_syntax
12
- .on_success { do_revoke_session }
13
- end
14
-
15
- private
16
-
17
- def do_check_id_syntax
18
- ::Booth::Syntaxes::Uuid.call(credential_id, raise_if_invalid: true)
19
- ::Booth::Syntaxes::Uuid.call(session_id, raise_if_invalid: true)
20
-
21
- Tron.success :valid_session_id_syntax
22
- end
23
-
24
- def do_revoke_session
25
- unless session
26
- debug { "Session #{session_id.inspect} not found for credential #{credential_id.inspect}" }
27
- return Tron.success :session_not_found
28
- end
29
-
30
- if session.revoked_at.present?
31
- debug { "Session #{session.id.inspect} is already revoked." }
32
- return Tron.success :already_revoked,
33
- public_message: I18n.t('booth.session_revoked', ip: session.most_recent_ip)
34
- end
35
-
36
- debug { "Revoking Session #{session.id.inspect}" }
37
- session.update! revoked_at: Time.current,
38
- revoke_reason: :manual
39
-
40
- Tron.success :session_revoked, public_message: I18n.t('booth.session_revoked', ip: session.most_recent_ip)
41
- end
42
-
43
- def session
44
- return @session if defined?(@session)
45
-
46
- @session = ::Booth::Models::Session.where(credential_id:)
47
- .find_by(id: session_id)
48
- end
49
- end
50
- end
51
- end
@@ -1,43 +0,0 @@
1
- module Booth
2
- module Sessions
3
- class RevokeAllOthers
4
- include ::Booth::MethodObject
5
-
6
- option :credential_id
7
- option :surviving_session_id
8
-
9
- def call
10
- do_check_id_syntax
11
- .on_success { do_revoke_all_other_session }
12
- end
13
-
14
- private
15
-
16
- def do_check_id_syntax
17
- ::Booth::Syntaxes::Uuid.call(credential_id, raise_if_invalid: true)
18
- ::Booth::Syntaxes::Uuid.call(surviving_session_id, raise_if_invalid: true)
19
-
20
- Tron.success :valid_session_id_syntax
21
- end
22
-
23
- def do_revoke_all_other_session
24
- if sessions.blank?
25
- return Tron.success :nothing_to_revoke, public_message: I18n.t('booth.all_other_sessions_revoked')
26
- end
27
-
28
- # Preferring speed. Because if there are many we don't want the page to hang.
29
- sessions.update_all revoked_at: Time.current,
30
- revoke_reason: :manual_all_others
31
-
32
- Tron.success :other_sessions_revoked, public_message: I18n.t('booth.all_other_sessions_revoked')
33
- end
34
-
35
- def sessions
36
- return @sessions if defined?(@sessions)
37
-
38
- @sessions = ::Booth::Models::Session.where(credential_id:)
39
- .where.not(id: surviving_session_id)
40
- end
41
- end
42
- end
43
- end
@@ -1,51 +0,0 @@
1
- module Booth
2
- module Sessions
3
- # A Passport is an immutable representation of your current browser-session.
4
- class ToPassport
5
- include ::Booth::MethodObject
6
- include ::Booth::Logging
7
-
8
- param :session
9
-
10
- def call
11
- ::Booth::ToStruct.call(attributes)
12
- end
13
-
14
- private
15
-
16
- delegate :credential, to: :session, private: true
17
-
18
- def attributes
19
- {
20
- id: session.id,
21
- username: credential.username,
22
- credential_id: credential.id,
23
- mode:,
24
- incognito_credential_id: session.incognito_credential_id,
25
- revoked_at: session.revoked_at,
26
- onboarding_secret_key:,
27
- is:,
28
- }
29
- end
30
-
31
- def is
32
- ::Booth::Credentials::Mode.new(credential)
33
- end
34
-
35
- def mode
36
- credential.mode.to_sym
37
- end
38
-
39
- def onboarding_secret_key
40
- return unless credential.mode_first_time?
41
-
42
- # If a first-time credential is in a logged in state,
43
- # that means this credential was just self-registered.
44
-
45
- # In that case, reveal the onboarding secret key,
46
- # so that the end-user may choose a login method for the first time.
47
- credential.onboarding&.secret_key
48
- end
49
- end
50
- end
51
- end
@@ -1,58 +0,0 @@
1
- module Booth
2
- module Syntaxes
3
- class ContestCode
4
- include ::Booth::Logging
5
- include ::Booth::MethodObject
6
-
7
- param :input
8
-
9
- def call
10
- debug { "Checking contest #{input.inspect} for valid syntax..." }
11
- check_blank.on_success { check_characters }
12
- .on_success { check_length }
13
- end
14
-
15
- private
16
-
17
- def check_blank
18
- return Tron.success :contest_code_present if input.present?
19
-
20
- debug { 'This contest is blank.' }
21
- Tron.failure :blank_contest_code,
22
- normalized_contest_code: nil,
23
- public_message: I18n.t('booth.blank_contest_code')
24
- end
25
-
26
- def check_characters
27
- return Tron.success :contest_code_consists_of_digits if input_without_spaces.match?(allowed_regexp)
28
-
29
- debug { 'This contest contains invalid characters' }
30
- Tron.failure :invalid_contest_code_format,
31
- normalized_contest_code: nil,
32
- public_message: I18n.t('booth.invalid_contest_code_format')
33
- end
34
-
35
- def check_length
36
- if input_without_spaces.to_s.length == ::Booth.config.contest_digits
37
- return Tron.success :valid_contest_code_syntax,
38
- normalized_contest_code: input_without_spaces
39
- end
40
-
41
- debug { "This contest is not #{::Booth.config.contest_digits} characters long." }
42
- Tron.failure :wrong_contest_code_length,
43
- normalized_contest_code: nil,
44
- public_message: I18n.t('booth.wrong_contest_code_length', digits: ::Booth.config.contest_digits)
45
- end
46
-
47
- # Helpers
48
-
49
- def input_without_spaces
50
- input.to_s.delete(' ')
51
- end
52
-
53
- def allowed_regexp
54
- /\A\d+\z/
55
- end
56
- end
57
- end
58
- end