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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/LICENSE.md +1 -2
- data/README.md +37 -6
- data/app/assets/images/booth/browsers/README.md +1 -2
- data/app/assets/images/booth/browsers/chrome.svg +1 -1
- data/app/assets/images/booth/browsers/edge.svg +1 -1
- data/app/assets/images/booth/browsers/firefox.svg +1 -1
- data/app/assets/images/booth/browsers/opera.svg +1 -1
- data/app/assets/images/booth/browsers/safari.svg +1 -1
- data/app/assets/images/booth/fido/passkey_mark_a.svg +10 -0
- data/app/assets/images/booth/fido/passkey_mark_a_black.svg +32 -0
- data/app/assets/images/booth/fido/passkey_mark_a_reverse.svg +33 -0
- data/app/assets/images/booth/fido/passkey_mark_a_white.svg +32 -0
- data/app/assets/images/booth/fido/passkey_mark_b_black.svg +1 -0
- data/app/assets/images/booth/platforms/android.svg +1 -6
- data/app/assets/images/booth/platforms/apple.svg +1 -6
- data/app/assets/images/booth/platforms/linux.svg +1 -6
- data/app/assets/images/booth/platforms/windows.svg +1 -6
- data/app/assets/javascripts/booth/authentication.js +29 -0
- data/app/assets/javascripts/booth/authentication.js.map +1 -0
- data/app/assets/javascripts/booth/error.js +38 -0
- data/app/assets/javascripts/booth/error.js.map +1 -0
- data/app/assets/javascripts/booth/form.js +78 -0
- data/app/assets/javascripts/booth/form.js.map +1 -0
- data/app/assets/javascripts/booth/gui.js +53 -0
- data/app/assets/javascripts/booth/gui.js.map +1 -0
- data/app/assets/javascripts/booth/registration.js +29 -0
- data/app/assets/javascripts/booth/registration.js.map +1 -0
- data/app/assets/javascripts/booth/setup.js +14 -0
- data/app/assets/javascripts/booth/verification.js +49 -0
- data/app/assets/javascripts/booth/verification.js.map +1 -0
- data/app/assets/javascripts/declarations/authentication.d.ts +6 -0
- data/app/assets/javascripts/declarations/error.d.ts +36 -0
- data/app/assets/javascripts/declarations/form.d.ts +8 -0
- data/app/assets/javascripts/declarations/gui.d.ts +4 -0
- data/app/assets/javascripts/declarations/registration.d.ts +6 -0
- data/app/assets/javascripts/declarations/setup.d.ts +3 -0
- data/app/assets/javascripts/declarations/verification.d.ts +6 -0
- data/app/assets/javascripts/src/authentication.ts +41 -0
- data/app/assets/javascripts/src/error.ts +35 -0
- data/app/assets/javascripts/src/form.ts +90 -0
- data/app/assets/javascripts/src/gui.ts +59 -0
- data/app/assets/javascripts/src/registration.ts +44 -0
- data/app/assets/javascripts/src/verification.ts +61 -0
- data/app/assets/stylesheets/booth/booth.css +3 -0
- data/config/importmap.rb +11 -0
- data/config/locales/de.yml +14 -38
- data/config/locales/en.yml +17 -36
- data/data/combined_aaguid.json +1 -0
- data/lib/booth/adminland/credentials/create.rb +10 -12
- data/lib/booth/adminland/credentials/index.rb +31 -0
- data/lib/booth/adminland/onboardings/create.rb +24 -15
- data/lib/booth/adminland/onboardings/destroy.rb +8 -4
- data/lib/booth/adminland/onboardings/find.rb +52 -45
- data/lib/booth/adminland/onboardings/find_unconsumed.rb +61 -0
- data/lib/booth/adminland/onboardings/index.rb +6 -3
- data/lib/booth/adminland/periodic_cleanup.rb +7 -2
- data/lib/booth/adminland.rb +17 -18
- data/lib/booth/coercers/domain.rb +11 -0
- data/lib/booth/coercers/request.rb +51 -0
- data/lib/booth/coercers/scope.rb +11 -0
- data/lib/booth/comparisons/domain.rb +38 -0
- data/lib/booth/comparisons/scope.rb +38 -0
- data/lib/booth/concerns/action.rb +25 -13
- data/lib/booth/concerns/transition.rb +5 -2
- data/lib/booth/configuration.rb +14 -73
- data/lib/booth/configure.rb +3 -10
- data/lib/booth/{audits/register → core/audit}/completed_onboarding.rb +8 -6
- data/lib/booth/core/audit/credential_created.rb +24 -0
- data/lib/booth/core/audit/logout.rb +24 -0
- data/lib/booth/core/authenticators/confirm.rb +30 -0
- data/lib/booth/core/authenticators/step.rb +24 -0
- data/lib/booth/core/cooldowns/distance_of_time.rb +50 -0
- data/lib/booth/core/cooldowns/strategies/exponential.rb +88 -0
- data/lib/booth/core/cooldowns/strategies/global.rb +66 -0
- data/lib/booth/core/cooldowns/strategies/result.rb +27 -0
- data/lib/booth/core/credentials/create.rb +32 -0
- data/lib/booth/core/credentials/find_by_username.rb +63 -0
- data/lib/booth/core/credentials/index.rb +15 -0
- data/lib/booth/core/credentials/webauth_challenge.rb +37 -0
- data/lib/booth/core/geolocation.rb +25 -0
- data/lib/booth/core/onboardings/find.rb +92 -0
- data/lib/booth/core/onboardings/step.rb +19 -0
- data/lib/booth/core/remotes/get.rb +45 -0
- data/lib/booth/core/remotes/respond.rb +82 -0
- data/lib/booth/core/remotes/set_for_login.rb +31 -0
- data/lib/booth/core/sessions/create_and_login.rb +63 -0
- data/lib/booth/core/sessions/historical_locations.rb +22 -0
- data/lib/booth/core/sessions/index.rb +66 -0
- data/lib/booth/core/sessions/revoke.rb +59 -0
- data/lib/booth/core/sessions/revoke_all_others.rb +49 -0
- data/lib/booth/core/sessions/to_passport.rb +35 -0
- data/lib/booth/core/webauth/authentication_verification.rb +76 -0
- data/lib/booth/core/webauth/options_for_create.rb +56 -0
- data/lib/booth/core/webauth/options_for_get.rb +30 -0
- data/lib/booth/core/webauth/provider.rb +36 -0
- data/lib/booth/core/webauth/registration_verification.rb +100 -0
- data/lib/booth/credential.rb +35 -0
- data/lib/booth/engine.rb +15 -4
- data/lib/booth/errors.rb +2 -0
- data/lib/booth/hooks/after_fetch.rb +14 -6
- data/lib/booth/hooks/before_logout.rb +5 -3
- data/lib/booth/hooks/serialize_from_session.rb +13 -5
- data/lib/booth/hooks/serialize_into_session.rb +6 -3
- data/lib/booth/logging.rb +13 -42
- data/lib/booth/models/application_record.rb +3 -0
- data/lib/booth/models/audit.rb +10 -11
- data/lib/booth/models/authenticator.rb +6 -9
- data/lib/booth/models/credential.rb +17 -20
- data/lib/booth/models/onboarding.rb +16 -39
- data/lib/booth/models/{contest.rb → remote.rb} +13 -14
- data/lib/booth/models/remotes/scopes/recently_created.rb +26 -0
- data/lib/booth/models/remotes/scopes/recently_responded.rb +35 -0
- data/lib/booth/models/session.rb +15 -10
- data/lib/booth/models/user_agent.rb +2 -0
- data/lib/booth/request.rb +43 -22
- data/lib/booth/requests/agent.rb +3 -1
- data/lib/booth/requests/authentication.rb +15 -5
- data/lib/booth/requests/ip.rb +4 -2
- data/lib/booth/requests/return_path.rb +4 -2
- data/lib/booth/requests/session.rb +6 -4
- data/lib/booth/requests/storage.rb +5 -31
- data/lib/booth/requests/storages/login.rb +35 -29
- data/lib/booth/requests/storages/registration.rb +2 -0
- data/lib/booth/requests/storages/webauth.rb +3 -0
- data/lib/booth/requests/sudo.rb +6 -50
- data/lib/booth/routes/userland.rb +13 -59
- data/lib/booth/syntaxes/domain.rb +46 -0
- data/lib/booth/syntaxes/email.rb +11 -8
- data/lib/booth/syntaxes/ip.rb +6 -4
- data/lib/booth/syntaxes/remote_code.rb +60 -0
- data/lib/booth/syntaxes/scope.rb +7 -3
- data/lib/booth/syntaxes/secret_key.rb +8 -6
- data/lib/booth/syntaxes/username.rb +23 -10
- data/lib/booth/syntaxes/uuid.rb +3 -1
- data/lib/booth/test.rb +27 -22
- data/lib/booth/testing/incorporation_test_case.rb +29 -0
- data/lib/booth/testing/shortcuts.rb +77 -0
- data/lib/booth/testing/support/assert_all_partials_were_covered.rb +69 -0
- data/lib/booth/testing/support/assert_logged_in.rb +68 -0
- data/lib/booth/{test → testing}/support/assert_logged_out.rb +7 -4
- data/lib/booth/testing/support/assert_partial.rb +56 -0
- data/lib/booth/{test → testing}/support/force_login.rb +10 -4
- data/lib/booth/{test → testing}/support/get_session_value.rb +8 -6
- data/lib/booth/testing/support/scenario.rb +23 -0
- data/lib/booth/testing/support/shortcuts/create_and_onboard.rb +56 -0
- data/lib/booth/testing/support/shortcuts/login_with_passkey.rb +55 -0
- data/lib/booth/testing/support/shortcuts/register_new_passkey.rb +51 -0
- data/lib/booth/testing/support/soft_reset_session.rb +24 -0
- data/lib/booth/testing/support/virtual_authenticators/create.rb +34 -0
- data/lib/booth/testing/support/virtual_authenticators/destroy.rb +20 -0
- data/lib/booth/testing/support/virtual_authenticators/enable.rb +24 -0
- data/lib/booth/testing/support/virtual_authenticators/load.rb +38 -0
- data/lib/booth/testing/support/virtual_authenticators/manager.rb +124 -0
- data/lib/booth/testing/support/visit.rb +62 -0
- data/lib/booth/testing/userland/login_remotely.rb +100 -0
- data/lib/booth/testing/userland/onboarding_first_time.rb +81 -0
- data/lib/booth/testing/userland/onboarding_to_reset_passkeys.rb +129 -0
- data/lib/booth/testing/userland/registration_with_passkey.rb +93 -0
- data/lib/booth/testing/userland/registration_without_passkey.rb +101 -0
- data/lib/booth/testing/userland/sessions_manage_behavior.rb +68 -0
- data/lib/booth/testing/userland/sessions_revoke_all_others.rb +17 -0
- data/lib/booth/testing/userland/sessions_revoke_one.rb +17 -0
- data/lib/booth/testing/userland.rb +36 -0
- data/lib/booth/to_struct.rb +9 -2
- data/lib/booth/userland/extract_flash_messages.rb +10 -3
- data/lib/booth/userland/logins/create.rb +8 -6
- data/lib/booth/userland/logins/destroy.rb +23 -6
- data/lib/booth/userland/logins/new.rb +23 -25
- data/lib/booth/userland/logins/transitions/create/choose_username.rb +62 -27
- data/lib/booth/userland/logins/transitions/create/skip_remotes.rb +18 -14
- data/lib/booth/userland/logins/transitions/create/webauth_authentication_initiation.rb +54 -48
- data/lib/booth/userland/logins/transitions/create/webauth_authentication_verification.rb +62 -58
- data/lib/booth/userland/logins/transitions/new/already_logged_in.rb +4 -3
- data/lib/booth/userland/logins/transitions/new/fallible.rb +4 -0
- data/lib/booth/userland/logins/transitions/new/{mode_username_and_password.rb → missing_authenticators.rb} +5 -4
- data/lib/booth/userland/logins/transitions/new/mode_username_and_webauth.rb +6 -4
- data/lib/booth/userland/logins/transitions/new/no_username_chosen.rb +3 -1
- data/lib/booth/userland/logins/transitions/new/remote_session_available.rb +20 -13
- data/lib/booth/userland/logins/transitions/new/timed_out.rb +3 -1
- data/lib/booth/userland/onboardings/show.rb +65 -39
- data/lib/booth/userland/onboardings/update.rb +46 -38
- data/lib/booth/userland/registrations/create.rb +51 -20
- data/lib/booth/userland/registrations/new.rb +6 -7
- data/lib/booth/userland/remotes/show.rb +56 -0
- data/lib/booth/userland/{personal_contests → remotes}/update.rb +5 -3
- data/lib/booth/userland/sessions/destroy_one_or_other.rb +3 -16
- data/lib/booth/userland/sessions/index.rb +4 -2
- data/lib/booth/userland/sessions/show.rb +5 -6
- data/lib/booth/userland/sessions/transitions/destroy/enter_webauth.rb +8 -6
- data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_initiation.rb +8 -6
- data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_verification.rb +7 -5
- data/lib/booth/userland/sessions/transitions/show/enter_webauth.rb +8 -6
- data/lib/booth/userland/webauths/create.rb +20 -17
- data/lib/booth/userland/webauths/destroy.rb +6 -16
- data/lib/booth/userland/webauths/guards/sudo.rb +10 -5
- data/lib/booth/userland/webauths/index.rb +4 -2
- data/lib/booth/userland/webauths/new.rb +7 -22
- data/lib/booth/userland/webauths/sudo.rb +3 -1
- data/lib/booth/userland/webauths/transitions/create/authentication_initiation.rb +8 -11
- data/lib/booth/userland/webauths/transitions/create/authentication_verification.rb +11 -13
- data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +8 -5
- data/lib/booth/userland/webauths/transitions/create/registration_initiation.rb +15 -14
- data/lib/booth/userland/webauths/transitions/create/registration_verification.rb +34 -28
- data/lib/booth/userland/webauths/transitions/create/reset.rb +2 -0
- data/lib/booth/userland/webauths/transitions/new/step.rb +3 -1
- data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +5 -10
- data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +4 -2
- data/lib/booth/userland.rb +53 -109
- data/lib/booth/version.rb +3 -1
- data/lib/booth.rb +6 -236
- data/lib/generators/booth/migration/migration_generator.rb +2 -1
- data/lib/generators/booth/migration/templates/add_credential_to_users.erb +6 -4
- data/lib/generators/booth/migration/templates/create_booth_tables.erb +61 -72
- metadata +124 -571
- data/app/assets/config/booth_manifest.js +0 -15
- data/app/assets/images/booth/browsers/internet_explorer.svg +0 -1
- data/app/assets/javascripts/booth/all.js +0 -162
- data/app/assets/javascripts/booth/all.js.map +0 -1
- data/app/assets/javascripts/booth/booth.ts +0 -194
- data/app/assets/javascripts/booth/webauthn-json.ts +0 -99
- data/lib/booth/adminland/recoveries/consume.rb +0 -70
- data/lib/booth/audits/register/added_otp.rb +0 -22
- data/lib/booth/audits/register/changed_otp.rb +0 -22
- data/lib/booth/audits/register/correct_otp.rb +0 -42
- data/lib/booth/audits/register/correct_password.rb +0 -43
- data/lib/booth/audits/register/logout.rb +0 -22
- data/lib/booth/audits/register/requested_password_reset.rb +0 -22
- data/lib/booth/audits/register/wrong_otp.rb +0 -22
- data/lib/booth/audits/register/wrong_password.rb +0 -25
- data/lib/booth/authenticators/confirm.rb +0 -34
- data/lib/booth/authenticators/credential_mode_after_confirmation.rb +0 -25
- data/lib/booth/authenticators/step.rb +0 -19
- data/lib/booth/contests/get.rb +0 -36
- data/lib/booth/contests/respond.rb +0 -78
- data/lib/booth/contests/set_for_login.rb +0 -28
- data/lib/booth/cooldowns/distance_of_time.rb +0 -46
- data/lib/booth/cooldowns/otp.rb +0 -22
- data/lib/booth/cooldowns/password.rb +0 -44
- data/lib/booth/cooldowns/password_reset.rb +0 -24
- data/lib/booth/cooldowns/strategies/exponential.rb +0 -82
- data/lib/booth/cooldowns/strategies/global.rb +0 -62
- data/lib/booth/cooldowns/strategies/result.rb +0 -22
- data/lib/booth/credentials/create.rb +0 -28
- data/lib/booth/credentials/create_with_onboarding.rb +0 -26
- data/lib/booth/credentials/find_by_username.rb +0 -45
- data/lib/booth/credentials/mode.rb +0 -69
- data/lib/booth/credentials/modes/otp_addable.rb +0 -23
- data/lib/booth/credentials/modes/otp_changeable.rb +0 -23
- data/lib/booth/credentials/modes/otp_manageable.rb +0 -17
- data/lib/booth/credentials/modes/otp_removable.rb +0 -23
- data/lib/booth/credentials/modes/password_addable.rb +0 -29
- data/lib/booth/credentials/modes/password_changeable.rb +0 -31
- data/lib/booth/credentials/modes/password_manageable.rb +0 -17
- data/lib/booth/credentials/modes/password_removable.rb +0 -24
- data/lib/booth/credentials/modes/password_removal_requires_user_verifiable_webauth.rb +0 -16
- data/lib/booth/credentials/modes/webauth_addable.rb +0 -26
- data/lib/booth/credentials/modes/webauth_manageable.rb +0 -16
- data/lib/booth/credentials/modes/webauth_removable.rb +0 -25
- data/lib/booth/credentials/otp_authentication.rb +0 -59
- data/lib/booth/credentials/password_authentication.rb +0 -72
- data/lib/booth/credentials/webauth_challenge.rb +0 -28
- data/lib/booth/geolocation.rb +0 -20
- data/lib/booth/logger.rb +0 -41
- data/lib/booth/method_object.rb +0 -73
- data/lib/booth/mode.rb +0 -22
- data/lib/booth/models/concerns/modeable.rb +0 -50
- data/lib/booth/models/concerns/otpable.rb +0 -37
- data/lib/booth/models/concerns/passwordable.rb +0 -58
- data/lib/booth/models/contests/scopes/recently_created.rb +0 -23
- data/lib/booth/models/contests/scopes/recently_responded.rb +0 -32
- data/lib/booth/models/password_reset.rb +0 -41
- data/lib/booth/models/recovery.rb +0 -32
- data/lib/booth/models/registration.rb +0 -10
- data/lib/booth/modes/base.rb +0 -25
- data/lib/booth/modes/username_and_password.rb +0 -7
- data/lib/booth/modes/username_and_webauth.rb +0 -7
- data/lib/booth/modes/username_password_and_otp.rb +0 -7
- data/lib/booth/modes/username_password_and_webauth.rb +0 -7
- data/lib/booth/onboardings/find.rb +0 -35
- data/lib/booth/onboardings/propagate_to_credential.rb +0 -63
- data/lib/booth/onboardings/step.rb +0 -68
- data/lib/booth/password_resets/create.rb +0 -57
- data/lib/booth/password_resets/find.rb +0 -36
- data/lib/booth/password_resets/propagate_to_credential.rb +0 -36
- data/lib/booth/password_resets/step.rb +0 -18
- data/lib/booth/recoveries/create.rb +0 -45
- data/lib/booth/requests/storages/otp.rb +0 -54
- data/lib/booth/requests/storages/password.rb +0 -49
- data/lib/booth/requests/storages/password_reset.rb +0 -35
- data/lib/booth/requests/storages/recovery.rb +0 -35
- data/lib/booth/sessions/create_and_login.rb +0 -46
- data/lib/booth/sessions/historical_locations.rb +0 -18
- data/lib/booth/sessions/index.rb +0 -59
- data/lib/booth/sessions/revoke.rb +0 -51
- data/lib/booth/sessions/revoke_all_others.rb +0 -43
- data/lib/booth/sessions/to_passport.rb +0 -51
- data/lib/booth/syntaxes/contest_code.rb +0 -58
- data/lib/booth/syntaxes/otp.rb +0 -57
- data/lib/booth/syntaxes/scope_comparison.rb +0 -28
- data/lib/booth/test/helpers.rb +0 -63
- data/lib/booth/test/support/assert_all_partials_were_covered.rb +0 -63
- data/lib/booth/test/support/assert_logged_in.rb +0 -49
- data/lib/booth/test/support/assert_partial.rb +0 -29
- data/lib/booth/test/support/otp_code_from_session.rb +0 -30
- data/lib/booth/test/support/soft_reset_session.rb +0 -22
- data/lib/booth/test/userland/logins/missing_authenticators.rb +0 -72
- data/lib/booth/test/userland/logins/missing_onboarding.rb +0 -35
- data/lib/booth/test/userland/logins/username_and_password.rb +0 -40
- data/lib/booth/test/userland/logins/username_and_webauth.rb +0 -75
- data/lib/booth/test/userland/logins/username_password_and_otp.rb +0 -45
- data/lib/booth/test/userland/logins/username_password_and_webauth.rb +0 -86
- data/lib/booth/test/userland/onboardings/already_logged_in.rb +0 -64
- data/lib/booth/test/userland/onboardings/otp.rb +0 -63
- data/lib/booth/test/userland/onboardings/password.rb +0 -49
- data/lib/booth/test/userland/onboardings/timeout.rb +0 -47
- data/lib/booth/test/userland/otps/manage.rb +0 -86
- data/lib/booth/test/userland/password_resets/reset.rb +0 -102
- data/lib/booth/test/userland.rb +0 -38
- data/lib/booth/test/webauthn/disable.rb +0 -17
- data/lib/booth/test/webauthn/enable.rb +0 -19
- data/lib/booth/test/webauthn/virtual_authenticators/create.rb +0 -38
- data/lib/booth/test/webauthn/virtual_authenticators/destroy.rb +0 -20
- data/lib/booth/userland/logins/transitions/create/enter_otp.rb +0 -70
- data/lib/booth/userland/logins/transitions/create/verify_password.rb +0 -70
- data/lib/booth/userland/logins/transitions/new/mode_first_time.rb +0 -20
- data/lib/booth/userland/logins/transitions/new/mode_username_password_and_otp.rb +0 -24
- data/lib/booth/userland/logins/transitions/new/mode_username_password_and_webauth.rb +0 -24
- data/lib/booth/userland/onboardings/transitions/update/choose_mode.rb +0 -58
- data/lib/booth/userland/onboardings/transitions/update/choose_password.rb +0 -41
- data/lib/booth/userland/onboardings/transitions/update/choose_webauth_nickname.rb +0 -50
- data/lib/booth/userland/onboardings/transitions/update/confirm_otp.rb +0 -58
- data/lib/booth/userland/onboardings/transitions/update/confirm_password.rb +0 -49
- data/lib/booth/userland/onboardings/transitions/update/register_otp.rb +0 -31
- data/lib/booth/userland/onboardings/transitions/update/reset_otp.rb +0 -40
- data/lib/booth/userland/onboardings/transitions/update/reset_password.rb +0 -35
- data/lib/booth/userland/onboardings/transitions/update/reset_webauth.rb +0 -46
- data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_initiation.rb +0 -40
- data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_verification.rb +0 -59
- data/lib/booth/userland/onboardings/transitions/update/webauth_registration_initiation.rb +0 -46
- data/lib/booth/userland/onboardings/transitions/update/webauth_registration_verification.rb +0 -56
- data/lib/booth/userland/otps/destroy.rb +0 -42
- data/lib/booth/userland/otps/edit.rb +0 -72
- data/lib/booth/userland/otps/guards/manageable.rb +0 -21
- data/lib/booth/userland/otps/guards/sudo.rb +0 -23
- data/lib/booth/userland/otps/show.rb +0 -36
- data/lib/booth/userland/otps/sudo.rb +0 -51
- data/lib/booth/userland/otps/transitions/update/confirm.rb +0 -84
- data/lib/booth/userland/otps/transitions/update/register.rb +0 -40
- data/lib/booth/userland/otps/transitions/update/reset.rb +0 -31
- data/lib/booth/userland/otps/update.rb +0 -34
- data/lib/booth/userland/password_resets/create.rb +0 -73
- data/lib/booth/userland/password_resets/guards/logged_out.rb +0 -21
- data/lib/booth/userland/password_resets/new.rb +0 -57
- data/lib/booth/userland/password_resets/show.rb +0 -77
- data/lib/booth/userland/password_resets/transitions/update/choose_password.rb +0 -48
- data/lib/booth/userland/password_resets/transitions/update/confirm_password.rb +0 -54
- data/lib/booth/userland/password_resets/transitions/update/reset_password.rb +0 -29
- data/lib/booth/userland/password_resets/update.rb +0 -65
- data/lib/booth/userland/passwords/destroy.rb +0 -41
- data/lib/booth/userland/passwords/edit.rb +0 -54
- data/lib/booth/userland/passwords/guards/manageable.rb +0 -21
- data/lib/booth/userland/passwords/guards/removable.rb +0 -21
- data/lib/booth/userland/passwords/guards/sudo.rb +0 -21
- data/lib/booth/userland/passwords/remove.rb +0 -34
- data/lib/booth/userland/passwords/show.rb +0 -32
- data/lib/booth/userland/passwords/sudo.rb +0 -55
- data/lib/booth/userland/passwords/transitions/remove/step.rb +0 -27
- data/lib/booth/userland/passwords/transitions/update/choose_password.rb +0 -62
- data/lib/booth/userland/passwords/transitions/update/confirm_password.rb +0 -82
- data/lib/booth/userland/passwords/update.rb +0 -33
- data/lib/booth/userland/personal_contests/show.rb +0 -60
- data/lib/booth/userland/recoveries/create.rb +0 -48
- data/lib/booth/userland/recoveries/new.rb +0 -35
- data/lib/booth/userland/sessions/transitions/destroy/enter_password.rb +0 -50
- data/lib/booth/userland/sessions/transitions/destroy/verify_password.rb +0 -83
- data/lib/booth/userland/webauths/guards/manageable.rb +0 -21
- data/lib/booth/webauth/authentication_verification.rb +0 -68
- data/lib/booth/webauth/demand_user_verification.rb +0 -29
- data/lib/booth/webauth/options_for_create.rb +0 -46
- data/lib/booth/webauth/options_for_get.rb +0 -29
- data/lib/generators/booth/migration/templates/create_booth_mode_types.erb +0 -20
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Testing
|
|
5
|
+
module Userland
|
|
6
|
+
class OnboardingToResetPasskeys < ::Booth::Testing::IncorporationTestCase
|
|
7
|
+
def call
|
|
8
|
+
before_test&.call
|
|
9
|
+
|
|
10
|
+
visit_namespaced controller: :onboardings, action: :show, params: { id: 'wrong-key' }
|
|
11
|
+
|
|
12
|
+
# ------------------------------ SIGNIFICANT TEST ---------------------------
|
|
13
|
+
# Onboardings can only be opened with the secret key, typos can be too short.
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
assert_userland_view controller: :onboardings, step: :not_found
|
|
16
|
+
|
|
17
|
+
credential = ::Booth::Models::Credential.create!(
|
|
18
|
+
domain: ::Capybara.app_host.remove('http://'),
|
|
19
|
+
username: 'alice',
|
|
20
|
+
scope:,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
after_credential&.call(credential_id: credential.id)
|
|
24
|
+
|
|
25
|
+
temporary_onboarding = ::Booth::Models::Onboarding.create!(
|
|
26
|
+
credential_id: credential.id,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
visit_namespaced controller: :onboardings, action: :show,
|
|
30
|
+
params: { id: temporary_onboarding.secret_key }
|
|
31
|
+
|
|
32
|
+
assert_userland_view controller: :onboardings, step: :redeem
|
|
33
|
+
click_on :submit
|
|
34
|
+
|
|
35
|
+
assert_logged_in username: 'alice'
|
|
36
|
+
|
|
37
|
+
temporary_onboarding.destroy!
|
|
38
|
+
onboarding = ::Booth::Models::Onboarding.create!(
|
|
39
|
+
credential_id: credential.id,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
visit_namespaced controller: :onboardings, action: :show,
|
|
43
|
+
params: { id: onboarding.secret_key }
|
|
44
|
+
|
|
45
|
+
# ----------------------- SIGNIFICANT TEST ---------------
|
|
46
|
+
# Logged in without Authenticators requires no Onboarding.
|
|
47
|
+
# --------------------------------------------------------
|
|
48
|
+
assert_userland_view controller: :onboardings, step: :not_needed
|
|
49
|
+
|
|
50
|
+
virtual_authenticators.create
|
|
51
|
+
visit_namespaced controller: :webauths, action: :new
|
|
52
|
+
|
|
53
|
+
assert_userland_view controller: :webauths, step: :register
|
|
54
|
+
|
|
55
|
+
click_on :register
|
|
56
|
+
|
|
57
|
+
assert_userland_view controller: :webauths, step: :choose_nickname
|
|
58
|
+
|
|
59
|
+
fill_in :nickname, with: 'Latchkey'
|
|
60
|
+
click_on :submit
|
|
61
|
+
|
|
62
|
+
assert_userland_view controller: :webauths, step: :confirm
|
|
63
|
+
click_on :test
|
|
64
|
+
|
|
65
|
+
assert_userland_view controller: :webauths, step: :completed
|
|
66
|
+
|
|
67
|
+
authenticator = ::Booth::Models::Authenticator.sole
|
|
68
|
+
|
|
69
|
+
assert_equal 'Latchkey', authenticator.nickname
|
|
70
|
+
|
|
71
|
+
soft_reset_session
|
|
72
|
+
|
|
73
|
+
# Onboard via URL
|
|
74
|
+
|
|
75
|
+
visit_namespaced controller: :onboardings, action: :show,
|
|
76
|
+
params: { id: onboarding.secret_key }
|
|
77
|
+
|
|
78
|
+
assert_userland_view controller: :onboardings, step: :redeem
|
|
79
|
+
|
|
80
|
+
click_on :submit
|
|
81
|
+
|
|
82
|
+
assert_equal 0, ::Booth::Models::Authenticator.count # (Side-effect, so we can avoid sudo)
|
|
83
|
+
|
|
84
|
+
visit_namespaced controller: :webauths, action: :new
|
|
85
|
+
|
|
86
|
+
# ------------------ SIGNIFICANT TEST -------------------
|
|
87
|
+
# Redeeming an Onboarding allows for adding new Passkeys.
|
|
88
|
+
# -------------------------------------------------------
|
|
89
|
+
assert_userland_view controller: :webauths, step: :register
|
|
90
|
+
|
|
91
|
+
click_on :register
|
|
92
|
+
|
|
93
|
+
assert_userland_view controller: :webauths, step: :choose_nickname
|
|
94
|
+
|
|
95
|
+
fill_in :nickname, with: 'Superkey'
|
|
96
|
+
click_on :submit
|
|
97
|
+
|
|
98
|
+
assert_userland_view controller: :webauths, step: :confirm
|
|
99
|
+
click_on :test
|
|
100
|
+
|
|
101
|
+
assert_userland_view controller: :webauths, step: :completed
|
|
102
|
+
|
|
103
|
+
authenticator = ::Booth::Models::Authenticator.sole
|
|
104
|
+
|
|
105
|
+
assert_equal 'Superkey', authenticator.nickname
|
|
106
|
+
|
|
107
|
+
travel 2.weeks
|
|
108
|
+
visit_namespaced controller: :onboardings, action: :show,
|
|
109
|
+
params: { id: onboarding.secret_key }
|
|
110
|
+
|
|
111
|
+
# ---------------------- SIGNIFICANT TEST -----------------
|
|
112
|
+
# Cannot open an old Onboarding (even if already consumed).
|
|
113
|
+
# ---------------------------------------------------------
|
|
114
|
+
assert_userland_view controller: :onboardings, step: :timed_out
|
|
115
|
+
|
|
116
|
+
::Booth::Models::Credential.sole.update!(blocked_at: Time.current)
|
|
117
|
+
|
|
118
|
+
visit_namespaced controller: :onboardings, action: :show,
|
|
119
|
+
params: { id: onboarding.secret_key }
|
|
120
|
+
|
|
121
|
+
# ---------------------- SIGNIFICANT TEST -----------------
|
|
122
|
+
# Cannot open an old Onboarding when Credential is blocked.
|
|
123
|
+
# ---------------------------------------------------------
|
|
124
|
+
assert_userland_view controller: :onboardings, step: :blocked
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Testing
|
|
5
|
+
module Userland
|
|
6
|
+
class RegistrationWithPasskey < ::Booth::Testing::IncorporationTestCase
|
|
7
|
+
def call
|
|
8
|
+
before_test&.call
|
|
9
|
+
|
|
10
|
+
# Register
|
|
11
|
+
|
|
12
|
+
visit_namespaced controller: :registrations, action: :new
|
|
13
|
+
|
|
14
|
+
return 'Skipping self-registration tests' if page.has_text?('HTTP ERROR 410') # Chrome Page
|
|
15
|
+
|
|
16
|
+
virtual_authenticators.create
|
|
17
|
+
|
|
18
|
+
assert_userland_view controller: :registrations, step: :choose_username
|
|
19
|
+
|
|
20
|
+
fill_in :username, with: 'alice'
|
|
21
|
+
click_on :submit
|
|
22
|
+
|
|
23
|
+
visit_namespaced controller: :webauths, action: :new
|
|
24
|
+
|
|
25
|
+
assert_userland_view controller: :webauths, step: :register
|
|
26
|
+
|
|
27
|
+
click_on :register
|
|
28
|
+
|
|
29
|
+
assert_userland_view controller: :webauths, step: :choose_nickname
|
|
30
|
+
|
|
31
|
+
fill_in :nickname, with: 'My Yubikey'
|
|
32
|
+
click_on :submit
|
|
33
|
+
|
|
34
|
+
assert_userland_view controller: :webauths, step: :confirm
|
|
35
|
+
click_on :test
|
|
36
|
+
|
|
37
|
+
# ------------ SIGNIFICANT TEST --------------
|
|
38
|
+
# Registering a Passkey via the Browser works.
|
|
39
|
+
# --------------------------------------------
|
|
40
|
+
assert_userland_view controller: :webauths, step: :completed
|
|
41
|
+
|
|
42
|
+
soft_reset_session
|
|
43
|
+
|
|
44
|
+
# Login
|
|
45
|
+
|
|
46
|
+
visit_namespaced controller: :logins, action: :new
|
|
47
|
+
|
|
48
|
+
assert_userland_view controller: :logins, step: :enter_username
|
|
49
|
+
|
|
50
|
+
fill_in :username, with: 'alice'
|
|
51
|
+
click_on :submit
|
|
52
|
+
|
|
53
|
+
# --------------------- SIGNIFICANT TEST -------------------------
|
|
54
|
+
# Without actually logging out, a Session is still regarded alive.
|
|
55
|
+
# ----------------------------------------------------------------
|
|
56
|
+
assert_userland_view controller: :logins, step: :remote_session_available
|
|
57
|
+
|
|
58
|
+
click_on :skip
|
|
59
|
+
|
|
60
|
+
assert_userland_view controller: :logins, step: :enter_webauth
|
|
61
|
+
|
|
62
|
+
# --------------------- SIGNIFICANT TEST --------------------------
|
|
63
|
+
# After registration and adding a Passkey, you can use it to login.
|
|
64
|
+
# -----------------------------------------------------------------
|
|
65
|
+
click_on :authenticate
|
|
66
|
+
|
|
67
|
+
visit_namespaced controller: :webauths, action: :index
|
|
68
|
+
|
|
69
|
+
assert_userland_view controller: :webauths, step: :index
|
|
70
|
+
|
|
71
|
+
# Try to register when already logged in
|
|
72
|
+
|
|
73
|
+
visit_namespaced controller: :registrations, action: :new
|
|
74
|
+
|
|
75
|
+
assert_userland_view controller: :registrations, step: :already_logged_in
|
|
76
|
+
|
|
77
|
+
visit_namespaced controller: :webauths, action: :new
|
|
78
|
+
|
|
79
|
+
assert_userland_view controller: :webauths, step: :register
|
|
80
|
+
|
|
81
|
+
click_on :register
|
|
82
|
+
|
|
83
|
+
assert_userland_view controller: :webauths, step: :register
|
|
84
|
+
|
|
85
|
+
# --------------------- SIGNIFICANT TEST ---------------
|
|
86
|
+
# A hardware device cannot be registered multiple times.
|
|
87
|
+
# ------------------------------------------------------
|
|
88
|
+
assert_text 'already registered with the relying party'
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Testing
|
|
5
|
+
module Userland
|
|
6
|
+
class RegistrationWithoutPasskey < ::Booth::Testing::IncorporationTestCase
|
|
7
|
+
def call
|
|
8
|
+
before_test&.call
|
|
9
|
+
|
|
10
|
+
# Register normally
|
|
11
|
+
|
|
12
|
+
visit_namespaced controller: :registrations, action: :new
|
|
13
|
+
|
|
14
|
+
# Chrome Page
|
|
15
|
+
return 'Skipping self-registration tests' if page.has_text?('HTTP ERROR 410')
|
|
16
|
+
|
|
17
|
+
assert_userland_view controller: :registrations, step: :choose_username
|
|
18
|
+
|
|
19
|
+
fill_in :username, with: 'alice'
|
|
20
|
+
click_on :submit
|
|
21
|
+
|
|
22
|
+
# Propagate login to other device
|
|
23
|
+
|
|
24
|
+
code = nil
|
|
25
|
+
using_session(:other_device) do
|
|
26
|
+
# Login
|
|
27
|
+
|
|
28
|
+
visit_namespaced controller: :logins, action: :new
|
|
29
|
+
|
|
30
|
+
assert_userland_view controller: :logins, step: :enter_username
|
|
31
|
+
|
|
32
|
+
fill_in :username, with: 'alice'
|
|
33
|
+
click_on :submit
|
|
34
|
+
|
|
35
|
+
assert_userland_view controller: :logins, step: :remote_session_available
|
|
36
|
+
|
|
37
|
+
code = find('[data-booth="code"]').text
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Redeem remote code
|
|
41
|
+
|
|
42
|
+
visit_namespaced controller: :remote_logins, action: :show
|
|
43
|
+
|
|
44
|
+
# ------------- SIGNIFICANT TEST -----------------
|
|
45
|
+
# After registering you are immediately logged in.
|
|
46
|
+
# ------------------------------------------------
|
|
47
|
+
|
|
48
|
+
assert_userland_view controller: :remote_logins, step: :remote_login
|
|
49
|
+
|
|
50
|
+
fill_in :code, with: code
|
|
51
|
+
click_on :submit
|
|
52
|
+
|
|
53
|
+
assert_userland_view controller: :remote_logins, step: :remote_solved
|
|
54
|
+
|
|
55
|
+
using_session(:other_device) do
|
|
56
|
+
visit_namespaced controller: :webauths, action: :index
|
|
57
|
+
|
|
58
|
+
# -------------------------- SIGNIFICANT TEST ---------------------------
|
|
59
|
+
# You can remote-login even though you don't have any Authenticators yet.
|
|
60
|
+
# -----------------------------------------------------------------------
|
|
61
|
+
assert_userland_view controller: :webauths, step: :index
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Try to Login without having any Authenticators
|
|
65
|
+
|
|
66
|
+
soft_reset_session
|
|
67
|
+
|
|
68
|
+
visit_namespaced controller: :logins, action: :new
|
|
69
|
+
|
|
70
|
+
assert_userland_view controller: :logins, step: :enter_username
|
|
71
|
+
|
|
72
|
+
fill_in :username, with: 'alice'
|
|
73
|
+
click_on :submit
|
|
74
|
+
|
|
75
|
+
assert_userland_view controller: :logins, step: :remote_session_available
|
|
76
|
+
|
|
77
|
+
click_on :skip
|
|
78
|
+
|
|
79
|
+
# ------------------ SIGNIFICANT TEST --------------------
|
|
80
|
+
# If you didn't register any Passkeys, you are locked out.
|
|
81
|
+
# --------------------------------------------------------
|
|
82
|
+
assert_userland_view controller: :logins, step: :no_authenticators
|
|
83
|
+
|
|
84
|
+
visit_namespaced controller: :registrations, action: :new
|
|
85
|
+
|
|
86
|
+
assert_userland_view controller: :registrations, step: :choose_username
|
|
87
|
+
|
|
88
|
+
fill_in :username, with: 'alice'
|
|
89
|
+
click_on :submit
|
|
90
|
+
|
|
91
|
+
assert_userland_view controller: :registrations, step: :choose_username
|
|
92
|
+
|
|
93
|
+
# ---------------- SIGNIFICANT TEST -------------------
|
|
94
|
+
# You cannot register a username that is already taken.
|
|
95
|
+
# -----------------------------------------------------
|
|
96
|
+
assert_text 'username already exists'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Testing
|
|
5
|
+
module Userland
|
|
6
|
+
module SessionsManageBehavior
|
|
7
|
+
include ::Booth::Logging
|
|
8
|
+
|
|
9
|
+
def run(button_name:, template:)
|
|
10
|
+
before_test&.call
|
|
11
|
+
|
|
12
|
+
create_and_onboard(username: 'alice')
|
|
13
|
+
virtual_authenticators.create
|
|
14
|
+
register_new_passkey(username: 'alice')
|
|
15
|
+
|
|
16
|
+
using_session(:"second_browser_#{button_name}") do
|
|
17
|
+
virtual_authenticators.clone_from_other_session
|
|
18
|
+
login_with_passkey(username: 'alice')
|
|
19
|
+
|
|
20
|
+
visit_namespaced controller: :sessions, action: :index
|
|
21
|
+
|
|
22
|
+
assert_userland_view controller: :sessions, step: :index
|
|
23
|
+
click_on button_name
|
|
24
|
+
|
|
25
|
+
# ----------------- SIGNIFICANT TEST -------------------
|
|
26
|
+
# Revoking another sessions keeps the current one alive.
|
|
27
|
+
# ------------------------------------------------------
|
|
28
|
+
assert_logged_in username: 'alice'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
visit current_path
|
|
32
|
+
|
|
33
|
+
# ----------- SIGNIFICANT TEST ---------------
|
|
34
|
+
# A revoked session is not logged in any more.
|
|
35
|
+
# --------------------------------------------
|
|
36
|
+
assert_logged_out
|
|
37
|
+
|
|
38
|
+
# Login on first device again and revoke all others
|
|
39
|
+
virtual_authenticators.refresh_from_other_session
|
|
40
|
+
login_with_passkey(username: 'alice')
|
|
41
|
+
|
|
42
|
+
visit_namespaced controller: :sessions, action: :index
|
|
43
|
+
|
|
44
|
+
assert_userland_view controller: :sessions, step: :index
|
|
45
|
+
travel 21.minutes
|
|
46
|
+
visit_namespaced controller: :sessions, action: :index
|
|
47
|
+
|
|
48
|
+
assert_userland_view controller: :sessions, step: :index
|
|
49
|
+
click_on button_name
|
|
50
|
+
|
|
51
|
+
assert_userland_view controller: :sessions, step: template
|
|
52
|
+
click_on :authenticate
|
|
53
|
+
|
|
54
|
+
assert_userland_view controller: :sessions, step: :index
|
|
55
|
+
|
|
56
|
+
using_session(:"second_browser_#{button_name}") do
|
|
57
|
+
visit_namespaced controller: :sessions, action: :index
|
|
58
|
+
|
|
59
|
+
# ----------- SIGNIFICANT TEST ---------------
|
|
60
|
+
# A revoked session is not logged in any more.
|
|
61
|
+
# --------------------------------------------
|
|
62
|
+
assert_logged_out
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'sessions_manage_behavior'
|
|
4
|
+
|
|
5
|
+
module Booth
|
|
6
|
+
module Testing
|
|
7
|
+
module Userland
|
|
8
|
+
class SessionsRevokeAllOthers < ::Booth::Testing::IncorporationTestCase
|
|
9
|
+
include SessionsManageBehavior
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
run(button_name: :revoke_all_others, template: :enter_webauth_to_destroy_all_others)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'sessions_manage_behavior'
|
|
4
|
+
|
|
5
|
+
module Booth
|
|
6
|
+
module Testing
|
|
7
|
+
module Userland
|
|
8
|
+
class SessionsRevokeOne < ::Booth::Testing::IncorporationTestCase
|
|
9
|
+
include SessionsManageBehavior
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
run(button_name: :revoke, template: :enter_webauth_to_destroy)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'support/shortcuts/create_and_onboard'
|
|
4
|
+
require_relative 'support/shortcuts/register_new_passkey'
|
|
5
|
+
require_relative 'support/shortcuts/login_with_passkey'
|
|
6
|
+
|
|
7
|
+
require_relative 'userland/login_remotely'
|
|
8
|
+
require_relative 'userland/onboarding_first_time'
|
|
9
|
+
require_relative 'userland/onboarding_to_reset_passkeys'
|
|
10
|
+
require_relative 'userland/registration_with_passkey'
|
|
11
|
+
require_relative 'userland/registration_without_passkey'
|
|
12
|
+
require_relative 'userland/sessions_manage_behavior'
|
|
13
|
+
require_relative 'userland/sessions_revoke_all_others'
|
|
14
|
+
require_relative 'userland/sessions_revoke_one'
|
|
15
|
+
|
|
16
|
+
module Booth
|
|
17
|
+
module Testing
|
|
18
|
+
module Userland
|
|
19
|
+
SCENARIOS = [
|
|
20
|
+
::Booth::Testing::Userland::RegistrationWithPasskey,
|
|
21
|
+
::Booth::Testing::Userland::RegistrationWithoutPasskey,
|
|
22
|
+
::Booth::Testing::Userland::OnboardingFirstTime,
|
|
23
|
+
::Booth::Testing::Userland::OnboardingToResetPasskeys,
|
|
24
|
+
::Booth::Testing::Userland::LoginRemotely,
|
|
25
|
+
::Booth::Testing::Userland::SessionsRevokeOne,
|
|
26
|
+
::Booth::Testing::Userland::SessionsRevokeAllOthers,
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
def self.scenarios
|
|
30
|
+
SCENARIOS.each do |klass|
|
|
31
|
+
yield ::Booth::Testing::Support::Scenario.new(klass)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/booth/to_struct.rb
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
4
|
+
# Converts a Hash to a Data object.
|
|
2
5
|
class ToStruct
|
|
3
|
-
include
|
|
6
|
+
include Calls
|
|
4
7
|
|
|
5
8
|
param :attributes
|
|
6
9
|
|
|
7
10
|
def call
|
|
8
|
-
::
|
|
11
|
+
::Data.define(*attributes.keys) do
|
|
12
|
+
def self.inspect
|
|
13
|
+
"<Data :#{members.join(', :')}>"
|
|
14
|
+
end
|
|
15
|
+
end.new(**attributes)
|
|
9
16
|
end
|
|
10
17
|
end
|
|
11
18
|
end
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Userland
|
|
3
5
|
class ExtractFlashMessages
|
|
4
6
|
include ::Booth::Logging
|
|
5
|
-
include
|
|
7
|
+
include Calls
|
|
6
8
|
|
|
9
|
+
# Where the message is extracted from.
|
|
10
|
+
# Example: `from: my_object` where my_object responds to #public_message
|
|
7
11
|
option :from
|
|
12
|
+
|
|
13
|
+
# Where the message is passed on to.
|
|
14
|
+
# Example: `to: flash` where flash responds to #notice=
|
|
8
15
|
option :to
|
|
9
16
|
|
|
10
17
|
def call
|
|
@@ -13,10 +20,10 @@ module Booth
|
|
|
13
20
|
return if from.public_message.blank?
|
|
14
21
|
|
|
15
22
|
if from.success?
|
|
16
|
-
|
|
23
|
+
log { "Saving flash notice: #{from.public_message}" }
|
|
17
24
|
to[:notice] = from.public_message
|
|
18
25
|
else
|
|
19
|
-
|
|
26
|
+
log { "Saving flash alert: #{from.public_message}" }
|
|
20
27
|
to[:alert] = from.public_message
|
|
21
28
|
end
|
|
22
29
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Userland
|
|
3
5
|
module Logins
|
|
6
|
+
# This Action receives a proof of identity (i.e. username or passkey)
|
|
7
|
+
# and either asks for more, or logs you in.
|
|
4
8
|
class Create
|
|
5
9
|
include ::Booth::Concerns::Action
|
|
6
10
|
|
|
@@ -14,12 +18,10 @@ module Booth
|
|
|
14
18
|
|
|
15
19
|
def transitions
|
|
16
20
|
[
|
|
17
|
-
::Booth::Logins::Transitions::Create::ChooseUsername,
|
|
18
|
-
::Booth::Logins::Transitions::Create::
|
|
19
|
-
::Booth::Logins::Transitions::Create::
|
|
20
|
-
::Booth::Logins::Transitions::Create::
|
|
21
|
-
::Booth::Logins::Transitions::Create::WebauthAuthenticationInitiation,
|
|
22
|
-
::Booth::Logins::Transitions::Create::WebauthAuthenticationVerification,
|
|
21
|
+
::Booth::Userland::Logins::Transitions::Create::ChooseUsername,
|
|
22
|
+
::Booth::Userland::Logins::Transitions::Create::SkipRemotes,
|
|
23
|
+
::Booth::Userland::Logins::Transitions::Create::WebauthAuthenticationInitiation,
|
|
24
|
+
::Booth::Userland::Logins::Transitions::Create::WebauthAuthenticationVerification
|
|
23
25
|
]
|
|
24
26
|
end
|
|
25
27
|
end
|
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Userland
|
|
3
5
|
module Logins
|
|
6
|
+
# This Action logs a user out.
|
|
4
7
|
class Destroy
|
|
5
8
|
include ::Booth::Concerns::Action
|
|
9
|
+
include ::Booth::Logging
|
|
6
10
|
|
|
7
|
-
def call
|
|
11
|
+
def call # rubocop:disable Metrics/AbcSize
|
|
8
12
|
request.must_be_delete!
|
|
9
13
|
request.must_be_html!
|
|
10
14
|
|
|
11
15
|
if request.authentication.logged_in?
|
|
12
16
|
public_message = I18n.t('booth.successfully_logged_out')
|
|
13
|
-
::Booth::
|
|
14
|
-
ip: request.ip,
|
|
15
|
-
agent: request.agent
|
|
17
|
+
::Booth::Core::Audit::Logout.call credential:, ip: request.ip, agent: request.agent
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
reset!
|
|
21
|
+
# cleanup_orphan_credential!
|
|
19
22
|
|
|
20
|
-
Tron.success :logged_out, return_path: request.return_path,
|
|
21
|
-
public_message:
|
|
23
|
+
Tron.success :logged_out, return_path: request.return_path, public_message:
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
private
|
|
25
27
|
|
|
26
28
|
def credential
|
|
29
|
+
return unless request.authentication.credential_id
|
|
30
|
+
|
|
27
31
|
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
28
32
|
end
|
|
29
33
|
|
|
@@ -31,6 +35,19 @@ module Booth
|
|
|
31
35
|
request.storage.login.reset
|
|
32
36
|
request.authentication.logout
|
|
33
37
|
end
|
|
38
|
+
|
|
39
|
+
# If this is a newly registered Credential, you were only logged in into this browser.
|
|
40
|
+
# If you didn't add any Authenticators, you cannot log in again later.
|
|
41
|
+
# Now that you logged out, your Credential is disposable and the username can be freed.
|
|
42
|
+
# def cleanup_orphan_credential!
|
|
43
|
+
# return unless credential # Logged out in another browser window.
|
|
44
|
+
# return if credential.authenticators.any?
|
|
45
|
+
|
|
46
|
+
# credential.destroy
|
|
47
|
+
# rescue StandardError
|
|
48
|
+
# # The destruction is allowed to fail if there are tables referencing this credential.
|
|
49
|
+
# log { "Could not remove Authenticator-less Credential #{credential.id}" }
|
|
50
|
+
# end
|
|
34
51
|
end
|
|
35
52
|
end
|
|
36
53
|
end
|
|
@@ -1,51 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Userland
|
|
5
|
+
# Actions in this namespace handle the login of a user.
|
|
3
6
|
module Logins
|
|
7
|
+
# This Action shows a login form for entering proof of identity (e.g. username, OTP).
|
|
4
8
|
class New
|
|
5
9
|
include ::Booth::Concerns::Action
|
|
6
10
|
|
|
7
|
-
def call
|
|
11
|
+
def call # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
8
12
|
request.must_be_get!
|
|
9
13
|
request.must_be_html!
|
|
10
14
|
|
|
11
15
|
if already_logged_in?
|
|
12
16
|
# Bail out early if it would conflict with another session.
|
|
13
|
-
# Because this could lead to
|
|
14
|
-
::Booth::Userland::Logins::Transitions::New::AlreadyLoggedIn.call(request:)
|
|
17
|
+
# Because this could lead to confusion for the end-user.
|
|
18
|
+
::Booth::Userland::Logins::Transitions::New::AlreadyLoggedIn.call(scope:, request:)
|
|
15
19
|
|
|
16
20
|
elsif storage.timed_out?
|
|
17
|
-
# The browser cookie just destroyed itself.
|
|
18
|
-
|
|
21
|
+
# The browser cookie just destroyed itself due to age.
|
|
22
|
+
# Whether logged in, or not, now you're considered logged out.
|
|
23
|
+
::Booth::Userland::Logins::Transitions::New::TimedOut.call(scope:, request:)
|
|
19
24
|
|
|
20
25
|
elsif storage.credential_for_username.blank?
|
|
21
|
-
#
|
|
26
|
+
# At this point we're ready to show the login form, asking for a username.
|
|
27
|
+
# In order to log someone in, we would first need a username.
|
|
22
28
|
# Without it we wouldn't know which credential to look for.
|
|
23
|
-
::Booth::Userland::Logins::Transitions::New::NoUsernameChosen.call(request:)
|
|
24
|
-
|
|
25
|
-
elsif storage.credential_for_username.mode_first_time?
|
|
26
|
-
# If that username is not initialized, bail out again.
|
|
27
|
-
# This should be an informative site with remedy information.
|
|
28
|
-
::Booth::Userland::Logins::Transitions::New::ModeFirstTime.call(request:)
|
|
29
|
+
::Booth::Userland::Logins::Transitions::New::NoUsernameChosen.call(scope:, request:)
|
|
29
30
|
|
|
30
31
|
elsif remote_session_available?
|
|
31
32
|
# If the user is logged in on another device,
|
|
32
33
|
# suggest that that device is used as a remote to login here.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
elsif storage.credential_for_username.mode_username_and_password?
|
|
36
|
-
::Booth::Userland::Logins::Transitions::New::ModeUsernameAndPassword.call(request:)
|
|
34
|
+
# This is possible even without registered authenticators.
|
|
35
|
+
::Booth::Userland::Logins::Transitions::New::RemoteSessionAvailable.call(scope:, request:)
|
|
37
36
|
|
|
38
|
-
elsif storage.credential_for_username.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
elsif storage.credential_for_username.mode_username_and_webauth?
|
|
45
|
-
::Booth::Userland::Logins::Transitions::New::ModeUsernameAndWebauth.call(request:)
|
|
37
|
+
elsif !storage.credential_for_username.registered_authenticators?
|
|
38
|
+
# If the username exists, but is not initialized, bail out.
|
|
39
|
+
# This could happen if the user self-registers, never adds a credential and logs out.
|
|
40
|
+
# This should be an informative site with remedy information.
|
|
41
|
+
# The remedy usually has the user go through an onboarding.
|
|
42
|
+
::Booth::Userland::Logins::Transitions::New::MissingAuthenticators.call(scope:, request:)
|
|
46
43
|
|
|
47
44
|
else
|
|
48
|
-
|
|
45
|
+
::Booth::Userland::Logins::Transitions::New::ModeUsernameAndWebauth.call(scope:, request:)
|
|
46
|
+
|
|
49
47
|
end
|
|
50
48
|
end
|
|
51
49
|
|