booth 0.0.1

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 (285) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +4 -0
  3. data/LICENSE.md +22 -0
  4. data/README.md +372 -0
  5. data/app/assets/config/booth_manifest.js +15 -0
  6. data/app/assets/images/booth/browsers/README.md +2 -0
  7. data/app/assets/images/booth/browsers/chrome.svg +1 -0
  8. data/app/assets/images/booth/browsers/edge.svg +1 -0
  9. data/app/assets/images/booth/browsers/firefox.svg +1 -0
  10. data/app/assets/images/booth/browsers/internet_explorer.svg +1 -0
  11. data/app/assets/images/booth/browsers/opera.svg +1 -0
  12. data/app/assets/images/booth/browsers/safari.svg +1 -0
  13. data/app/assets/images/booth/browsers/unknown.svg +1 -0
  14. data/app/assets/images/booth/platforms/README.md +2 -0
  15. data/app/assets/images/booth/platforms/android.svg +6 -0
  16. data/app/assets/images/booth/platforms/apple.svg +6 -0
  17. data/app/assets/images/booth/platforms/linux.svg +6 -0
  18. data/app/assets/images/booth/platforms/unknown.svg +1 -0
  19. data/app/assets/images/booth/platforms/windows.svg +6 -0
  20. data/app/assets/javascripts/booth/all.js +162 -0
  21. data/app/assets/javascripts/booth/all.js.map +1 -0
  22. data/app/assets/javascripts/booth/booth.ts +194 -0
  23. data/app/assets/javascripts/booth/webauthn-json.ts +99 -0
  24. data/config/locales/de.yml +84 -0
  25. data/config/locales/en.yml +79 -0
  26. data/lib/booth/adminland/credentials/create.rb +30 -0
  27. data/lib/booth/adminland/onboardings/create.rb +63 -0
  28. data/lib/booth/adminland/onboardings/destroy.rb +50 -0
  29. data/lib/booth/adminland/onboardings/find.rb +93 -0
  30. data/lib/booth/adminland/onboardings/index.rb +23 -0
  31. data/lib/booth/adminland/periodic_cleanup.rb +11 -0
  32. data/lib/booth/adminland/recoveries/consume.rb +70 -0
  33. data/lib/booth/adminland.rb +48 -0
  34. data/lib/booth/audits/register/added_otp.rb +22 -0
  35. data/lib/booth/audits/register/changed_otp.rb +22 -0
  36. data/lib/booth/audits/register/completed_onboarding.rb +22 -0
  37. data/lib/booth/audits/register/correct_otp.rb +42 -0
  38. data/lib/booth/audits/register/correct_password.rb +43 -0
  39. data/lib/booth/audits/register/logout.rb +22 -0
  40. data/lib/booth/audits/register/requested_password_reset.rb +22 -0
  41. data/lib/booth/audits/register/wrong_otp.rb +22 -0
  42. data/lib/booth/audits/register/wrong_password.rb +25 -0
  43. data/lib/booth/authenticators/confirm.rb +34 -0
  44. data/lib/booth/authenticators/credential_mode_after_confirmation.rb +25 -0
  45. data/lib/booth/authenticators/step.rb +19 -0
  46. data/lib/booth/concerns/action.rb +58 -0
  47. data/lib/booth/concerns/transition.rb +17 -0
  48. data/lib/booth/configuration.rb +116 -0
  49. data/lib/booth/configure.rb +37 -0
  50. data/lib/booth/contests/get.rb +36 -0
  51. data/lib/booth/contests/respond.rb +78 -0
  52. data/lib/booth/contests/set_for_login.rb +28 -0
  53. data/lib/booth/cooldowns/distance_of_time.rb +46 -0
  54. data/lib/booth/cooldowns/otp.rb +22 -0
  55. data/lib/booth/cooldowns/password.rb +44 -0
  56. data/lib/booth/cooldowns/password_reset.rb +24 -0
  57. data/lib/booth/cooldowns/strategies/exponential.rb +82 -0
  58. data/lib/booth/cooldowns/strategies/global.rb +62 -0
  59. data/lib/booth/cooldowns/strategies/result.rb +22 -0
  60. data/lib/booth/credentials/create.rb +28 -0
  61. data/lib/booth/credentials/create_with_onboarding.rb +26 -0
  62. data/lib/booth/credentials/find_by_username.rb +45 -0
  63. data/lib/booth/credentials/mode.rb +69 -0
  64. data/lib/booth/credentials/modes/otp_addable.rb +23 -0
  65. data/lib/booth/credentials/modes/otp_changeable.rb +23 -0
  66. data/lib/booth/credentials/modes/otp_manageable.rb +17 -0
  67. data/lib/booth/credentials/modes/otp_removable.rb +23 -0
  68. data/lib/booth/credentials/modes/password_addable.rb +29 -0
  69. data/lib/booth/credentials/modes/password_changeable.rb +31 -0
  70. data/lib/booth/credentials/modes/password_manageable.rb +17 -0
  71. data/lib/booth/credentials/modes/password_removable.rb +24 -0
  72. data/lib/booth/credentials/modes/password_removal_requires_user_verifiable_webauth.rb +16 -0
  73. data/lib/booth/credentials/modes/webauth_addable.rb +26 -0
  74. data/lib/booth/credentials/modes/webauth_manageable.rb +16 -0
  75. data/lib/booth/credentials/modes/webauth_removable.rb +25 -0
  76. data/lib/booth/credentials/otp_authentication.rb +59 -0
  77. data/lib/booth/credentials/password_authentication.rb +72 -0
  78. data/lib/booth/credentials/webauth_challenge.rb +28 -0
  79. data/lib/booth/engine.rb +25 -0
  80. data/lib/booth/errors.rb +86 -0
  81. data/lib/booth/geolocation.rb +20 -0
  82. data/lib/booth/hooks/after_fetch.rb +54 -0
  83. data/lib/booth/hooks/before_logout.rb +29 -0
  84. data/lib/booth/hooks/serialize_from_session.rb +24 -0
  85. data/lib/booth/hooks/serialize_into_session.rb +14 -0
  86. data/lib/booth/logger.rb +41 -0
  87. data/lib/booth/logging.rb +59 -0
  88. data/lib/booth/method_object.rb +73 -0
  89. data/lib/booth/mode.rb +22 -0
  90. data/lib/booth/models/application_record.rb +7 -0
  91. data/lib/booth/models/audit.rb +24 -0
  92. data/lib/booth/models/authenticator.rb +45 -0
  93. data/lib/booth/models/concerns/modeable.rb +50 -0
  94. data/lib/booth/models/concerns/otpable.rb +37 -0
  95. data/lib/booth/models/concerns/passwordable.rb +58 -0
  96. data/lib/booth/models/contest.rb +55 -0
  97. data/lib/booth/models/contests/scopes/recently_created.rb +23 -0
  98. data/lib/booth/models/contests/scopes/recently_responded.rb +32 -0
  99. data/lib/booth/models/credential.rb +61 -0
  100. data/lib/booth/models/onboarding.rb +61 -0
  101. data/lib/booth/models/password_reset.rb +41 -0
  102. data/lib/booth/models/recovery.rb +32 -0
  103. data/lib/booth/models/registration.rb +10 -0
  104. data/lib/booth/models/session.rb +47 -0
  105. data/lib/booth/models/user_agent.rb +50 -0
  106. data/lib/booth/modes/base.rb +25 -0
  107. data/lib/booth/modes/username_and_password.rb +7 -0
  108. data/lib/booth/modes/username_and_webauth.rb +7 -0
  109. data/lib/booth/modes/username_password_and_otp.rb +7 -0
  110. data/lib/booth/modes/username_password_and_webauth.rb +7 -0
  111. data/lib/booth/onboardings/find.rb +35 -0
  112. data/lib/booth/onboardings/propagate_to_credential.rb +63 -0
  113. data/lib/booth/onboardings/step.rb +68 -0
  114. data/lib/booth/password_resets/create.rb +57 -0
  115. data/lib/booth/password_resets/find.rb +36 -0
  116. data/lib/booth/password_resets/propagate_to_credential.rb +36 -0
  117. data/lib/booth/password_resets/step.rb +18 -0
  118. data/lib/booth/recoveries/create.rb +45 -0
  119. data/lib/booth/request.rb +106 -0
  120. data/lib/booth/requests/agent.rb +14 -0
  121. data/lib/booth/requests/authentication.rb +47 -0
  122. data/lib/booth/requests/ip.rb +28 -0
  123. data/lib/booth/requests/return_path.rb +34 -0
  124. data/lib/booth/requests/session.rb +106 -0
  125. data/lib/booth/requests/storage.rb +62 -0
  126. data/lib/booth/requests/storages/login.rb +108 -0
  127. data/lib/booth/requests/storages/otp.rb +54 -0
  128. data/lib/booth/requests/storages/password.rb +49 -0
  129. data/lib/booth/requests/storages/password_reset.rb +35 -0
  130. data/lib/booth/requests/storages/recovery.rb +35 -0
  131. data/lib/booth/requests/storages/registration.rb +27 -0
  132. data/lib/booth/requests/storages/webauth.rb +38 -0
  133. data/lib/booth/requests/sudo.rb +110 -0
  134. data/lib/booth/routes/userland.rb +80 -0
  135. data/lib/booth/sessions/create_and_login.rb +46 -0
  136. data/lib/booth/sessions/historical_locations.rb +18 -0
  137. data/lib/booth/sessions/index.rb +59 -0
  138. data/lib/booth/sessions/revoke.rb +51 -0
  139. data/lib/booth/sessions/revoke_all_others.rb +43 -0
  140. data/lib/booth/sessions/to_passport.rb +51 -0
  141. data/lib/booth/syntaxes/contest_code.rb +58 -0
  142. data/lib/booth/syntaxes/email.rb +97 -0
  143. data/lib/booth/syntaxes/ip.rb +37 -0
  144. data/lib/booth/syntaxes/otp.rb +57 -0
  145. data/lib/booth/syntaxes/scope.rb +21 -0
  146. data/lib/booth/syntaxes/scope_comparison.rb +28 -0
  147. data/lib/booth/syntaxes/secret_key.rb +64 -0
  148. data/lib/booth/syntaxes/username.rb +85 -0
  149. data/lib/booth/syntaxes/uuid.rb +23 -0
  150. data/lib/booth/test/helpers.rb +63 -0
  151. data/lib/booth/test/support/assert_all_partials_were_covered.rb +63 -0
  152. data/lib/booth/test/support/assert_logged_in.rb +49 -0
  153. data/lib/booth/test/support/assert_logged_out.rb +30 -0
  154. data/lib/booth/test/support/assert_partial.rb +29 -0
  155. data/lib/booth/test/support/force_login.rb +26 -0
  156. data/lib/booth/test/support/get_session_value.rb +35 -0
  157. data/lib/booth/test/support/otp_code_from_session.rb +30 -0
  158. data/lib/booth/test/support/soft_reset_session.rb +22 -0
  159. data/lib/booth/test/userland/logins/missing_authenticators.rb +72 -0
  160. data/lib/booth/test/userland/logins/missing_onboarding.rb +35 -0
  161. data/lib/booth/test/userland/logins/username_and_password.rb +40 -0
  162. data/lib/booth/test/userland/logins/username_and_webauth.rb +75 -0
  163. data/lib/booth/test/userland/logins/username_password_and_otp.rb +45 -0
  164. data/lib/booth/test/userland/logins/username_password_and_webauth.rb +86 -0
  165. data/lib/booth/test/userland/onboardings/already_logged_in.rb +64 -0
  166. data/lib/booth/test/userland/onboardings/otp.rb +63 -0
  167. data/lib/booth/test/userland/onboardings/password.rb +49 -0
  168. data/lib/booth/test/userland/onboardings/timeout.rb +47 -0
  169. data/lib/booth/test/userland/otps/manage.rb +86 -0
  170. data/lib/booth/test/userland/password_resets/reset.rb +102 -0
  171. data/lib/booth/test/userland.rb +38 -0
  172. data/lib/booth/test/webauthn/disable.rb +17 -0
  173. data/lib/booth/test/webauthn/enable.rb +19 -0
  174. data/lib/booth/test/webauthn/virtual_authenticators/create.rb +38 -0
  175. data/lib/booth/test/webauthn/virtual_authenticators/destroy.rb +20 -0
  176. data/lib/booth/test.rb +53 -0
  177. data/lib/booth/to_struct.rb +11 -0
  178. data/lib/booth/userland/extract_flash_messages.rb +35 -0
  179. data/lib/booth/userland/logins/create.rb +28 -0
  180. data/lib/booth/userland/logins/destroy.rb +37 -0
  181. data/lib/booth/userland/logins/new.rb +70 -0
  182. data/lib/booth/userland/logins/transitions/create/choose_username.rb +41 -0
  183. data/lib/booth/userland/logins/transitions/create/enter_otp.rb +70 -0
  184. data/lib/booth/userland/logins/transitions/create/skip_remotes.rb +24 -0
  185. data/lib/booth/userland/logins/transitions/create/verify_password.rb +70 -0
  186. data/lib/booth/userland/logins/transitions/create/webauth_authentication_initiation.rb +55 -0
  187. data/lib/booth/userland/logins/transitions/create/webauth_authentication_verification.rb +80 -0
  188. data/lib/booth/userland/logins/transitions/new/already_logged_in.rb +21 -0
  189. data/lib/booth/userland/logins/transitions/new/fallible.rb +27 -0
  190. data/lib/booth/userland/logins/transitions/new/mode_first_time.rb +20 -0
  191. data/lib/booth/userland/logins/transitions/new/mode_username_and_password.rb +20 -0
  192. data/lib/booth/userland/logins/transitions/new/mode_username_and_webauth.rb +26 -0
  193. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_otp.rb +24 -0
  194. data/lib/booth/userland/logins/transitions/new/mode_username_password_and_webauth.rb +24 -0
  195. data/lib/booth/userland/logins/transitions/new/no_username_chosen.rb +19 -0
  196. data/lib/booth/userland/logins/transitions/new/remote_session_available.rb +52 -0
  197. data/lib/booth/userland/logins/transitions/new/timed_out.rb +25 -0
  198. data/lib/booth/userland/onboardings/show.rb +74 -0
  199. data/lib/booth/userland/onboardings/transitions/update/choose_mode.rb +58 -0
  200. data/lib/booth/userland/onboardings/transitions/update/choose_password.rb +41 -0
  201. data/lib/booth/userland/onboardings/transitions/update/choose_webauth_nickname.rb +50 -0
  202. data/lib/booth/userland/onboardings/transitions/update/confirm_otp.rb +58 -0
  203. data/lib/booth/userland/onboardings/transitions/update/confirm_password.rb +49 -0
  204. data/lib/booth/userland/onboardings/transitions/update/register_otp.rb +31 -0
  205. data/lib/booth/userland/onboardings/transitions/update/reset_otp.rb +40 -0
  206. data/lib/booth/userland/onboardings/transitions/update/reset_password.rb +35 -0
  207. data/lib/booth/userland/onboardings/transitions/update/reset_webauth.rb +46 -0
  208. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_initiation.rb +40 -0
  209. data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_verification.rb +59 -0
  210. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_initiation.rb +46 -0
  211. data/lib/booth/userland/onboardings/transitions/update/webauth_registration_verification.rb +56 -0
  212. data/lib/booth/userland/onboardings/update.rb +68 -0
  213. data/lib/booth/userland/otps/destroy.rb +42 -0
  214. data/lib/booth/userland/otps/edit.rb +72 -0
  215. data/lib/booth/userland/otps/guards/manageable.rb +21 -0
  216. data/lib/booth/userland/otps/guards/sudo.rb +23 -0
  217. data/lib/booth/userland/otps/show.rb +36 -0
  218. data/lib/booth/userland/otps/sudo.rb +51 -0
  219. data/lib/booth/userland/otps/transitions/update/confirm.rb +84 -0
  220. data/lib/booth/userland/otps/transitions/update/register.rb +40 -0
  221. data/lib/booth/userland/otps/transitions/update/reset.rb +31 -0
  222. data/lib/booth/userland/otps/update.rb +34 -0
  223. data/lib/booth/userland/password_resets/create.rb +73 -0
  224. data/lib/booth/userland/password_resets/guards/logged_out.rb +21 -0
  225. data/lib/booth/userland/password_resets/new.rb +57 -0
  226. data/lib/booth/userland/password_resets/show.rb +77 -0
  227. data/lib/booth/userland/password_resets/transitions/update/choose_password.rb +48 -0
  228. data/lib/booth/userland/password_resets/transitions/update/confirm_password.rb +54 -0
  229. data/lib/booth/userland/password_resets/transitions/update/reset_password.rb +29 -0
  230. data/lib/booth/userland/password_resets/update.rb +65 -0
  231. data/lib/booth/userland/passwords/destroy.rb +41 -0
  232. data/lib/booth/userland/passwords/edit.rb +54 -0
  233. data/lib/booth/userland/passwords/guards/manageable.rb +21 -0
  234. data/lib/booth/userland/passwords/guards/removable.rb +21 -0
  235. data/lib/booth/userland/passwords/guards/sudo.rb +21 -0
  236. data/lib/booth/userland/passwords/remove.rb +34 -0
  237. data/lib/booth/userland/passwords/show.rb +32 -0
  238. data/lib/booth/userland/passwords/sudo.rb +55 -0
  239. data/lib/booth/userland/passwords/transitions/remove/step.rb +27 -0
  240. data/lib/booth/userland/passwords/transitions/update/choose_password.rb +62 -0
  241. data/lib/booth/userland/passwords/transitions/update/confirm_password.rb +82 -0
  242. data/lib/booth/userland/passwords/update.rb +33 -0
  243. data/lib/booth/userland/personal_contests/show.rb +60 -0
  244. data/lib/booth/userland/personal_contests/update.rb +37 -0
  245. data/lib/booth/userland/recoveries/create.rb +48 -0
  246. data/lib/booth/userland/recoveries/new.rb +35 -0
  247. data/lib/booth/userland/registrations/create.rb +56 -0
  248. data/lib/booth/userland/registrations/new.rb +39 -0
  249. data/lib/booth/userland/sessions/destroy_one_or_other.rb +41 -0
  250. data/lib/booth/userland/sessions/index.rb +27 -0
  251. data/lib/booth/userland/sessions/show.rb +31 -0
  252. data/lib/booth/userland/sessions/transitions/destroy/enter_password.rb +50 -0
  253. data/lib/booth/userland/sessions/transitions/destroy/enter_webauth.rb +56 -0
  254. data/lib/booth/userland/sessions/transitions/destroy/verify_password.rb +83 -0
  255. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_initiation.rb +38 -0
  256. data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_verification.rb +61 -0
  257. data/lib/booth/userland/sessions/transitions/show/enter_webauth.rb +56 -0
  258. data/lib/booth/userland/webauths/create.rb +83 -0
  259. data/lib/booth/userland/webauths/destroy.rb +60 -0
  260. data/lib/booth/userland/webauths/guards/manageable.rb +21 -0
  261. data/lib/booth/userland/webauths/guards/sudo.rb +22 -0
  262. data/lib/booth/userland/webauths/index.rb +43 -0
  263. data/lib/booth/userland/webauths/new.rb +70 -0
  264. data/lib/booth/userland/webauths/sudo.rb +25 -0
  265. data/lib/booth/userland/webauths/transitions/create/authentication_initiation.rb +52 -0
  266. data/lib/booth/userland/webauths/transitions/create/authentication_verification.rb +64 -0
  267. data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +50 -0
  268. data/lib/booth/userland/webauths/transitions/create/registration_initiation.rb +61 -0
  269. data/lib/booth/userland/webauths/transitions/create/registration_verification.rb +68 -0
  270. data/lib/booth/userland/webauths/transitions/create/reset.rb +36 -0
  271. data/lib/booth/userland/webauths/transitions/new/step.rb +23 -0
  272. data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +47 -0
  273. data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +34 -0
  274. data/lib/booth/userland.rb +192 -0
  275. data/lib/booth/version.rb +3 -0
  276. data/lib/booth/webauth/authentication_verification.rb +68 -0
  277. data/lib/booth/webauth/demand_user_verification.rb +29 -0
  278. data/lib/booth/webauth/options_for_create.rb +46 -0
  279. data/lib/booth/webauth/options_for_get.rb +29 -0
  280. data/lib/booth.rb +267 -0
  281. data/lib/generators/booth/migration/migration_generator.rb +25 -0
  282. data/lib/generators/booth/migration/templates/add_credential_to_users.erb +18 -0
  283. data/lib/generators/booth/migration/templates/create_booth_mode_types.erb +20 -0
  284. data/lib/generators/booth/migration/templates/create_booth_tables.erb +135 -0
  285. metadata +861 -0
@@ -0,0 +1,29 @@
1
+ module Booth
2
+ module Test
3
+ module Support
4
+ class AssertPartial
5
+ include ::Booth::MethodObject
6
+
7
+ cattr_accessor :asserted_partials, instance_accessor: false, default: Set.new
8
+
9
+ option :page
10
+ option :namespace
11
+ option :controller
12
+ option :step
13
+
14
+ def call
15
+ ::Capybara::Lockstep.synchronize
16
+
17
+ page.find "[data-booth='#{partial}']", visible: :all
18
+
19
+ self.class.asserted_partials << partial
20
+ nil
21
+ end
22
+
23
+ def partial
24
+ "#{namespace}/#{controller}/#{step}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ module Booth
2
+ module Test
3
+ module Support
4
+ class ForceLogin
5
+ include ::Booth::MethodObject
6
+
7
+ option :credential_id
8
+ option :request, ::Booth::Request
9
+
10
+ def call
11
+ ::Booth::Sessions::CreateAndLogin.call(credential:, request:)
12
+ end
13
+
14
+ delegate :scope, to: :credential
15
+
16
+ private
17
+
18
+ def credential
19
+ return @credential if defined?(@credential)
20
+
21
+ @credential = ::Booth::Models::Credential.find_by(id: credential_id)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ module Booth
2
+ module Test
3
+ module Support
4
+ class GetSessionValue
5
+ include ::Booth::MethodObject
6
+ include ::Booth::Logging
7
+
8
+ option :page
9
+ option :key
10
+
11
+ def call
12
+ ::Capybara::Lockstep.synchronize
13
+
14
+ result = nil
15
+ in_new_window do
16
+ result = page.get_rack_session[key]
17
+ end
18
+
19
+ debug { "session[#{key.inspect}] is: #{result.inspect}" }
20
+
21
+ ::Capybara::Lockstep.synchronize
22
+ result
23
+ end
24
+
25
+ private
26
+
27
+ def in_new_window(&)
28
+ window = page.open_new_window
29
+ page.within_window(window, &)
30
+ window.close
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ module Booth
2
+ module Test
3
+ module Support
4
+ class OtpCodeFromSession
5
+ include ::Booth::MethodObject
6
+
7
+ option :page
8
+ option :scope
9
+
10
+ def call
11
+ secret_key = load_secret_key
12
+ raise 'No OTP secret key found in session' if secret_key.blank?
13
+
14
+ dummy = ::Booth::Models::Credential.new otp_secret_key: secret_key
15
+ dummy.otp_code
16
+ end
17
+
18
+ private
19
+
20
+ def load_secret_key
21
+ ::Booth::Test::Support::GetSessionValue.call(page:, key:)
22
+ end
23
+
24
+ def key
25
+ "booth.#{scope}.otp.secret_key"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ module Booth
2
+ module Test
3
+ module Support
4
+ # Essentially resets the session cookie, but without removing
5
+ # Chrome's Virtual Authenticator Enviroment.
6
+ class SoftResetSession
7
+ include ::Booth::MethodObject
8
+
9
+ option :page
10
+
11
+ def call
12
+ ::Capybara::Lockstep.synchronize
13
+
14
+ keys = page.get_rack_session.keys
15
+ nilified_keys = keys.index_with { nil }
16
+
17
+ page.set_rack_session(**nilified_keys)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,72 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class MissingAuthenticators
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+ option :new_login_path
13
+
14
+ def call
15
+ credential = ::Booth::Models::Credential.create!(
16
+ username: 'alice',
17
+ password: 'qwrasfyxv',
18
+ scope:,
19
+ mode: :username_and_webauth,
20
+ allowed_modes: [:username_and_webauth]
21
+ )
22
+
23
+ onboarding = ::Booth::Models::Onboarding.create!(
24
+ credential_id: credential.id,
25
+ mode: :username_and_webauth
26
+ )
27
+
28
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
29
+
30
+ create_virtual_authenticator
31
+
32
+ assert_userland_partial controller: :onboarding, step: :register_webauth
33
+
34
+ page.click_on :register
35
+
36
+ assert_userland_partial controller: :onboarding, step: :choose_webauth_nickname
37
+
38
+ page.fill_in :nickname, with: 'Yubikey'
39
+ page.click_on :submit
40
+
41
+ assert_userland_partial controller: :onboarding, step: :confirm_webauth
42
+
43
+ page.click_on :authenticate
44
+
45
+ assert_userland_partial controller: :onboarding, step: :completed
46
+ assert_logged_in credential: credential
47
+
48
+ soft_reset_session
49
+ assert_logged_out
50
+
51
+ credential.authenticators.delete_all
52
+
53
+ # Login
54
+
55
+ page.visit new_login_path
56
+
57
+ assert_userland_partial controller: :login, step: :enter_username
58
+
59
+ page.fill_in :username, with: 'alice'
60
+ page.click_on :submit
61
+
62
+ assert_userland_partial controller: :login, step: :remote_session_available
63
+
64
+ page.click_on :skip
65
+
66
+ assert_userland_partial controller: :login, step: :no_authenticators
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class MissingOnboarding
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :new_login_path
12
+
13
+ def call
14
+ ::Booth::Models::Credential.create!(
15
+ username: 'alice',
16
+ password: 'qwrasfyxv',
17
+ scope:,
18
+ mode: :first_time,
19
+ allowed_modes: [:username_and_password]
20
+ )
21
+
22
+ page.visit new_login_path
23
+
24
+ assert_userland_partial controller: :login, step: :enter_username
25
+
26
+ page.fill_in :username, with: 'alice'
27
+ page.click_on :submit
28
+
29
+ assert_userland_partial controller: :login, step: :needs_onboarding
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class UsernameAndPassword
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :new_login_path
12
+
13
+ def call
14
+ credential = ::Booth::Models::Credential.create!(
15
+ username: 'alice',
16
+ password: 'qwrasfyxv',
17
+ scope:,
18
+ mode: :username_and_password,
19
+ allowed_modes: [:username_and_password]
20
+ )
21
+
22
+ page.visit new_login_path
23
+
24
+ assert_userland_partial controller: :login, step: :enter_username
25
+
26
+ page.fill_in :username, with: 'alice'
27
+ page.click_on :submit
28
+
29
+ assert_userland_partial controller: :login, step: :enter_password
30
+
31
+ page.fill_in :password, with: 'qwrasfyxv'
32
+ page.click_on :submit
33
+
34
+ assert_logged_in credential:
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,75 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class UsernameAndWebauth
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+ option :new_login_path
13
+ option :after_credential, default: -> {}
14
+
15
+ def call
16
+ credential = ::Booth::Models::Credential.create!(
17
+ username: 'alice',
18
+ password: 'qwrasfyxv',
19
+ scope:,
20
+ mode: :username_and_webauth,
21
+ allowed_modes: [:username_and_webauth]
22
+ )
23
+ after_credential&.call(credential.id)
24
+
25
+ onboarding = ::Booth::Models::Onboarding.create!(
26
+ credential_id: credential.id,
27
+ mode: :username_and_webauth
28
+ )
29
+
30
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
31
+ create_virtual_authenticator
32
+
33
+ assert_userland_partial controller: :onboarding, step: :register_webauth
34
+
35
+ page.click_on :register
36
+
37
+ assert_userland_partial controller: :onboarding, step: :choose_webauth_nickname
38
+
39
+ page.fill_in :nickname, with: 'Yubikey'
40
+ page.click_on :submit
41
+
42
+ assert_userland_partial controller: :onboarding, step: :confirm_webauth
43
+
44
+ page.click_on :authenticate
45
+
46
+ assert_userland_partial controller: :onboarding, step: :completed
47
+ assert_logged_in credential: credential
48
+
49
+ soft_reset_session
50
+ assert_logged_out
51
+
52
+ # Login
53
+
54
+ page.visit new_login_path
55
+
56
+ assert_userland_partial controller: :login, step: :enter_username
57
+
58
+ page.fill_in :username, with: 'alice'
59
+ page.click_on :submit
60
+
61
+ assert_userland_partial controller: :login, step: :remote_session_available
62
+
63
+ page.click_on :skip
64
+
65
+ assert_userland_partial controller: :login, step: :enter_webauth
66
+
67
+ page.click_on :authenticate
68
+
69
+ assert_logged_in credential:
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,45 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class UsernamePasswordAndOtp
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :new_login_path
12
+
13
+ def call
14
+ credential = ::Booth::Models::Credential.create!(
15
+ username: 'alice',
16
+ password: 'qwrasfyxv',
17
+ scope:,
18
+ mode: :username_password_and_otp,
19
+ allowed_modes: [:username_password_and_otp]
20
+ )
21
+
22
+ page.visit new_login_path
23
+
24
+ assert_userland_partial controller: :login, step: :enter_username
25
+
26
+ page.fill_in :username, with: 'alice'
27
+ page.click_on :submit
28
+
29
+ assert_userland_partial controller: :login, step: :enter_password
30
+
31
+ page.fill_in :password, with: 'qwrasfyxv'
32
+ page.click_on :submit
33
+
34
+ assert_userland_partial controller: :login, step: :enter_otp
35
+
36
+ page.fill_in :code, with: credential.otp_code
37
+ page.click_on :submit
38
+
39
+ assert_logged_in credential:
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,86 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Logins
5
+ class UsernamePasswordAndWebauth
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+ option :new_login_path
13
+
14
+ def call
15
+ # Setup
16
+
17
+ credential = ::Booth::Models::Credential.create!(
18
+ username: 'alice',
19
+ password: 'qwrasfyxv',
20
+ scope:,
21
+ mode: :username_password_and_webauth,
22
+ allowed_modes: [:username_password_and_webauth]
23
+ )
24
+
25
+ onboarding = ::Booth::Models::Onboarding.create!(
26
+ credential_id: credential.id,
27
+ mode: :username_password_and_webauth
28
+ )
29
+
30
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
31
+ create_virtual_authenticator
32
+
33
+ assert_userland_partial controller: :onboarding, step: :choose_password
34
+
35
+ # Choose password
36
+
37
+ page.fill_in :password, with: 'qwrasfyxv'
38
+ page.click_on :submit
39
+
40
+ page.fill_in :password, with: 'qwrasfyxv'
41
+ page.click_on :submit
42
+
43
+ # Choose Webauth
44
+
45
+ page.click_on :register
46
+ page.fill_in :nickname, with: 'Yubikey'
47
+ page.click_on :submit
48
+
49
+ page.click_on :authenticate
50
+
51
+ assert_userland_partial controller: :onboarding, step: :completed
52
+ assert_logged_in credential: credential
53
+
54
+ soft_reset_session
55
+ assert_logged_out
56
+
57
+ # Login
58
+
59
+ page.visit new_login_path
60
+
61
+ assert_userland_partial controller: :login, step: :enter_username
62
+
63
+ page.fill_in :username, with: 'alice'
64
+ page.click_on :submit
65
+
66
+ assert_userland_partial controller: :login, step: :remote_session_available
67
+ # TODO: Not really needed if there were no other active session (created by onboarding)
68
+ page.click_on :skip
69
+
70
+ assert_userland_partial controller: :login, step: :enter_password
71
+
72
+ page.fill_in :password, with: 'qwrasfyxv'
73
+ page.click_on :submit
74
+
75
+ assert_userland_partial controller: :login, step: :enter_webauth
76
+
77
+ page.click_on :authenticate
78
+ sleep 1
79
+
80
+ assert_logged_in credential:
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,64 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Onboardings
5
+ class AlreadyLoggedIn
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+ option :new_login_path
13
+
14
+ def call
15
+ # Setup
16
+
17
+ alice = ::Booth::Models::Credential.create!(
18
+ username: 'alice',
19
+ password: 'qwrasfyxv',
20
+ scope:,
21
+ mode: :username_and_password,
22
+ allowed_modes: [:username_and_password]
23
+ )
24
+
25
+ bobby = ::Booth::Models::Credential.create!(
26
+ username: 'bobby',
27
+ password: 'qwrasfyxv',
28
+ scope:,
29
+ mode: :username_and_password,
30
+ allowed_modes: [:username_and_password]
31
+ )
32
+
33
+ onboarding = ::Booth::Models::Onboarding.create!(
34
+ credential_id: bobby.id,
35
+ mode: :username_and_password
36
+ )
37
+
38
+ # Loging in Alice
39
+
40
+ page.visit new_login_path
41
+
42
+ assert_userland_partial controller: :login, step: :enter_username
43
+
44
+ page.fill_in :username, with: 'alice'
45
+ page.click_on :submit
46
+
47
+ assert_userland_partial controller: :login, step: :enter_password
48
+
49
+ page.fill_in :password, with: 'qwrasfyxv'
50
+ page.click_on :submit
51
+
52
+ assert_logged_in credential: alice
53
+
54
+ # Onboarding as Bobby
55
+
56
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
57
+
58
+ assert_userland_partial controller: :onboarding, step: :already_logged_in
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,63 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Onboardings
5
+ class Otp
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+ option :new_login_path
13
+
14
+ def call
15
+ # Setup
16
+
17
+ credential = ::Booth::Models::Credential.create!(
18
+ username: 'alice',
19
+ password: 'qwrasfyxv',
20
+ scope:,
21
+ mode: :username_password_and_otp,
22
+ allowed_modes: %i[username_password_and_otp username_and_webauth]
23
+ )
24
+
25
+ onboarding = ::Booth::Models::Onboarding.create!(
26
+ credential_id: credential.id,
27
+ mode: :first_time
28
+ )
29
+
30
+ # Onboarding
31
+
32
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
33
+
34
+ assert_userland_partial controller: :onboarding, step: :choose_mode
35
+
36
+ page.click_on :choose_username_password_and_otp
37
+
38
+ assert_userland_partial controller: :onboarding, step: :choose_password
39
+
40
+ page.fill_in :password, with: 'qwrasfyxv'
41
+ page.click_on :submit
42
+
43
+ assert_userland_partial controller: :onboarding, step: :confirm_password
44
+
45
+ page.fill_in :password, with: 'qwrasfyxv'
46
+ page.click_on :submit
47
+
48
+ assert_userland_partial controller: :onboarding, step: :register_otp
49
+
50
+ page.click_on :confirm
51
+
52
+ assert_userland_partial controller: :onboarding, step: :confirm_otp
53
+
54
+ page.fill_in :code, with: onboarding.reload.otp_code
55
+ page.click_on :submit
56
+
57
+ assert_logged_in credential:
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,49 @@
1
+ module Booth
2
+ module Test
3
+ module Userland
4
+ module Onboardings
5
+ class Password
6
+ include ::Booth::MethodObject
7
+ include ::Booth::Test::Helpers
8
+
9
+ option :page
10
+ option :scope
11
+ option :show_onboarding_path
12
+
13
+ def call
14
+ # Setup
15
+
16
+ credential = ::Booth::Models::Credential.create!(
17
+ username: 'alice',
18
+ password: 'qwrasfyxv',
19
+ scope:,
20
+ mode: :username_and_password,
21
+ allowed_modes: %i[username_and_password username_and_webauth]
22
+ )
23
+
24
+ onboarding = ::Booth::Models::Onboarding.create!(
25
+ credential_id: credential.id,
26
+ mode: :first_time
27
+ )
28
+
29
+ # Onboarding
30
+
31
+ page.visit show_onboarding_path.sub('ID', onboarding.secret_key)
32
+
33
+ assert_userland_partial controller: :onboarding, step: :choose_mode
34
+
35
+ page.click_on :choose_username_and_password
36
+
37
+ page.fill_in :password, with: 'qwrasfyxv'
38
+ page.click_on :submit
39
+
40
+ page.fill_in :password, with: 'qwrasfyxv'
41
+ page.click_on :submit
42
+
43
+ assert_logged_in credential:
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end