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
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Concerns
|
|
3
|
-
# An "Action" is something that is called from a Rails controller
|
|
5
|
+
# An "Action" is something that is called from a Rails controller.
|
|
4
6
|
# It contains all the logic that the controller action is supposed to execute.
|
|
5
7
|
# By convention the "authentication scope" and the "request object" are passed in.
|
|
6
8
|
module Action
|
|
@@ -8,10 +10,10 @@ module Booth
|
|
|
8
10
|
|
|
9
11
|
included do
|
|
10
12
|
include ::Booth::Logging
|
|
11
|
-
include
|
|
13
|
+
include Calls
|
|
12
14
|
|
|
13
|
-
option :scope,
|
|
14
|
-
option :request, ::Booth::Request
|
|
15
|
+
option :scope, ::Booth::Coercers::Scope
|
|
16
|
+
option :request, ::Booth::Coercers::Request
|
|
15
17
|
|
|
16
18
|
delegate :params, to: :request, private: true
|
|
17
19
|
end
|
|
@@ -22,36 +24,46 @@ module Booth
|
|
|
22
24
|
# May be overriden
|
|
23
25
|
# ----------------
|
|
24
26
|
|
|
27
|
+
# An Action implements at least this method. It holds an Array of Transition classes.
|
|
28
|
+
#
|
|
29
|
+
# If a Transition feels responsible for handling the incoming params,
|
|
30
|
+
# it is instantiated and called, to change the state of the user authentication.
|
|
31
|
+
def transitions
|
|
32
|
+
raise "Implement `#transitions` in #{self}"
|
|
33
|
+
end
|
|
34
|
+
|
|
25
35
|
def initialize_transition
|
|
26
|
-
transition.call(request:)
|
|
36
|
+
transition.call(scope:, request:)
|
|
27
37
|
end
|
|
28
38
|
|
|
29
39
|
def after_transition; end
|
|
30
40
|
|
|
31
|
-
def transitions
|
|
32
|
-
raise "Implement `#transitions` in #{self}"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
41
|
# ---------------
|
|
36
42
|
# Never overriden
|
|
37
43
|
# ---------------
|
|
38
44
|
|
|
39
45
|
# I found this to be a repetitive pattern, so I added this method in this concern.
|
|
40
|
-
# It makes the code a little harder to read but probably
|
|
46
|
+
# It makes the code a little harder to read but probably more robust.
|
|
41
47
|
def do_transition
|
|
42
48
|
if transition
|
|
43
|
-
|
|
49
|
+
message = if ENV['DEBUG']
|
|
50
|
+
"🔹 TRANSITION - #{transition.to_s.demodulize}"
|
|
51
|
+
else
|
|
52
|
+
"Calling Transition #{transition}"
|
|
53
|
+
end
|
|
54
|
+
log { message }
|
|
55
|
+
|
|
44
56
|
result = initialize_transition
|
|
45
57
|
after_transition
|
|
46
58
|
return result
|
|
47
59
|
end
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
log { "❌ No transition applies to these params: #{params.keys.join(', ')}" }
|
|
50
62
|
Tron.failure :unknown_transition
|
|
51
63
|
end
|
|
52
64
|
|
|
53
65
|
def transition
|
|
54
|
-
@transition ||= transitions.detect {
|
|
66
|
+
@transition ||= transitions.detect { it.applicable?(params:) }
|
|
55
67
|
end
|
|
56
68
|
end
|
|
57
69
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Concerns
|
|
3
5
|
# A `Booth::Action` usually consists of several `Booth::Transition`s.
|
|
@@ -6,9 +8,10 @@ module Booth
|
|
|
6
8
|
|
|
7
9
|
included do
|
|
8
10
|
include ::Booth::Logging
|
|
9
|
-
include
|
|
11
|
+
include Calls
|
|
10
12
|
|
|
11
|
-
option :
|
|
13
|
+
option :scope, ::Booth::Coercers::Scope
|
|
14
|
+
option :request, ::Booth::Coercers::Request
|
|
12
15
|
|
|
13
16
|
delegate :params, to: :request, private: true
|
|
14
17
|
end
|
data/lib/booth/configuration.rb
CHANGED
|
@@ -1,31 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
# Holds global configuration parameters.
|
|
3
5
|
class Configuration
|
|
4
|
-
def
|
|
5
|
-
@
|
|
6
|
+
def initialize
|
|
7
|
+
@logger = rails_logger
|
|
8
|
+
@session_inactivity_lifetime = 1.year
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
# Need to keep the name `request:` here, because it is checked when calling the lambda.
|
|
11
|
+
@relying_party_resolver = lambda { |request:| # rubocop:disable Lint/UnusedBlockArgument
|
|
12
|
+
raise 'Please set a Booth.config.relying_party_resolver'
|
|
13
|
+
}
|
|
8
14
|
end
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
@otp_issuers ||= {}
|
|
12
|
-
|
|
13
|
-
@otp_issuers[scope.to_sym] = new_issuer
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def otp_issuer=(new_issuer)
|
|
17
|
-
set_otp_issuer(new_issuer)
|
|
18
|
-
end
|
|
16
|
+
attr_accessor :logger, :session_inactivity_lifetime, :relying_party_resolver
|
|
19
17
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@logger || rails_logger
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def logger=(new_logger)
|
|
27
|
-
@no_logger = new_logger.nil?
|
|
28
|
-
@logger = new_logger
|
|
18
|
+
def interaction_timeout
|
|
19
|
+
20.minutes
|
|
29
20
|
end
|
|
30
21
|
|
|
31
22
|
def log_to_rails_and_stdout!
|
|
@@ -34,47 +25,9 @@ module Booth
|
|
|
34
25
|
::Booth.config.send(:rails_logger).debug(...)
|
|
35
26
|
::Booth.config.send(:stdout_logger).debug(...)
|
|
36
27
|
end
|
|
37
|
-
|
|
38
|
-
def warn(...)
|
|
39
|
-
::Booth.config.send(:rails_logger).warn(...)
|
|
40
|
-
::Booth.config.send(:stdout_logger).warn(...)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def error(...)
|
|
44
|
-
::Booth.config.send(:rails_logger).error(...)
|
|
45
|
-
::Booth.config.send(:stdout_logger).error(...)
|
|
46
|
-
end
|
|
47
28
|
end.new
|
|
48
29
|
end
|
|
49
30
|
|
|
50
|
-
def interaction_timeout
|
|
51
|
-
20.minutes
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def session_inactivity_lifetime
|
|
55
|
-
@session_inactivity_lifetime ||= 3.months
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def session_inactivity_lifetime=(new_lifetime)
|
|
59
|
-
@session_inactivity_lifetime = new_lifetime
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def password_reset_window
|
|
63
|
-
2.hours
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def onboarding_window
|
|
67
|
-
1.week
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def otp_digits
|
|
71
|
-
6
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def contest_digits
|
|
75
|
-
6
|
|
76
|
-
end
|
|
77
|
-
|
|
78
31
|
private
|
|
79
32
|
|
|
80
33
|
# The standard Rails logger does not show `progname`.
|
|
@@ -82,19 +35,7 @@ module Booth
|
|
|
82
35
|
def rails_logger
|
|
83
36
|
@rails_logger ||= Class.new do
|
|
84
37
|
def debug(progname, &block)
|
|
85
|
-
::Rails.logger.debug { "#{
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def info(progname, &block)
|
|
89
|
-
::Rails.logger.info { "#{ActiveSupport::LogSubscriber.new.send(:color, progname, :blue)} - #{block.call}" }
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def warn(progname, &block)
|
|
93
|
-
::Rails.logger.warn { "#{ActiveSupport::LogSubscriber.new.send(:color, progname, :blue)} - #{block.call}" }
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def error(progname, &block)
|
|
97
|
-
::Rails.logger.error { "#{ActiveSupport::LogSubscriber.new.send(:color, progname, :blue)} - #{block.call}" }
|
|
38
|
+
::Rails.logger.debug { "#{Paint[progname, :blue]} - #{block.call}" }
|
|
98
39
|
end
|
|
99
40
|
end.new
|
|
100
41
|
end
|
|
@@ -109,7 +50,7 @@ module Booth
|
|
|
109
50
|
|
|
110
51
|
def stdout_logger_formatter
|
|
111
52
|
proc do |severity, _, progname, message|
|
|
112
|
-
|
|
53
|
+
"#{severity.rjust(5)} #{Paint[progname, :blue]} - #{message}\n"
|
|
113
54
|
end
|
|
114
55
|
end
|
|
115
56
|
end
|
data/lib/booth/configure.rb
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The main module for this Ruby gem.
|
|
1
4
|
module Booth
|
|
2
5
|
# Lazy-loads and returns the global configuration instance.
|
|
3
6
|
#
|
|
@@ -24,14 +27,4 @@ module Booth
|
|
|
24
27
|
def self.configure
|
|
25
28
|
yield config
|
|
26
29
|
end
|
|
27
|
-
|
|
28
|
-
# Resets the configuration.
|
|
29
|
-
#
|
|
30
|
-
# @note This is useful for testing, since the configuration is global
|
|
31
|
-
# and persists across tests.
|
|
32
|
-
# @api private
|
|
33
|
-
#
|
|
34
|
-
def self.reset!
|
|
35
|
-
@configs = nil
|
|
36
|
-
end
|
|
37
30
|
end
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
|
-
module
|
|
3
|
-
module
|
|
4
|
+
module Core
|
|
5
|
+
module Audit
|
|
4
6
|
class CompletedOnboarding
|
|
5
|
-
include
|
|
7
|
+
include Calls
|
|
6
8
|
|
|
7
9
|
option :credential
|
|
8
10
|
option :ip
|
|
9
11
|
option :agent
|
|
10
12
|
|
|
11
13
|
def call
|
|
12
|
-
::Booth::Models::Audit.create! credential
|
|
13
|
-
ip
|
|
14
|
-
agent
|
|
14
|
+
::Booth::Models::Audit.create! credential:,
|
|
15
|
+
ip:,
|
|
16
|
+
agent:,
|
|
15
17
|
event: :completed_onboarding
|
|
16
18
|
|
|
17
19
|
nil
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Audit
|
|
6
|
+
class CredentialCreated
|
|
7
|
+
include Calls
|
|
8
|
+
|
|
9
|
+
option :credential
|
|
10
|
+
option :ip
|
|
11
|
+
option :agent
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
::Booth::Models::Audit.create! credential:,
|
|
15
|
+
ip:,
|
|
16
|
+
agent:,
|
|
17
|
+
event: :registered
|
|
18
|
+
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Audit
|
|
6
|
+
class Logout
|
|
7
|
+
include Calls
|
|
8
|
+
|
|
9
|
+
option :credential
|
|
10
|
+
option :ip
|
|
11
|
+
option :agent
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
::Booth::Models::Audit.create! credential:,
|
|
15
|
+
ip:,
|
|
16
|
+
agent:,
|
|
17
|
+
event: :logout
|
|
18
|
+
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Authenticators
|
|
6
|
+
class Confirm
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :authenticator
|
|
11
|
+
option :sign_count
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
raise 'Authenticator is already confirmed' if authenticator.confirmed_at
|
|
15
|
+
|
|
16
|
+
log { 'Confirming Authenticator...' }
|
|
17
|
+
authenticator.transaction do
|
|
18
|
+
authenticator.update! sign_count:,
|
|
19
|
+
confirmed_at: Time.current
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Tron.success :confirmation_successful
|
|
23
|
+
rescue ActiveRecord::ActiveRecordError => e
|
|
24
|
+
error { e }
|
|
25
|
+
Tron.failure :confirmation_failed
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Authenticators
|
|
6
|
+
# Registration status of an Authenticator.
|
|
7
|
+
class Step
|
|
8
|
+
include Calls
|
|
9
|
+
|
|
10
|
+
param :authenticator
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
return :register if authenticator.device_id.blank? ||
|
|
14
|
+
authenticator.public_key.blank? ||
|
|
15
|
+
authenticator.sign_count.blank?
|
|
16
|
+
return :choose_nickname if authenticator.nickname.blank?
|
|
17
|
+
return :confirm if authenticator.confirmed_at.blank?
|
|
18
|
+
|
|
19
|
+
:completed
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Cooldowns
|
|
6
|
+
class DistanceOfTime
|
|
7
|
+
include Calls
|
|
8
|
+
|
|
9
|
+
option :from
|
|
10
|
+
option :till
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
result = []
|
|
14
|
+
result.push("#{distance_in_hours} h") if show_hours?
|
|
15
|
+
result.push("#{distance_in_minutes} min") if show_minutes?
|
|
16
|
+
result.push("#{distance_in_seconds} s") if show_seconds?
|
|
17
|
+
result.join(' ')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def show_hours?
|
|
21
|
+
distance_in_hours.positive?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def show_minutes?
|
|
25
|
+
return false if (((till - from).abs % 3600) / 60) < 1
|
|
26
|
+
|
|
27
|
+
distance_in_minutes.nonzero?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def show_seconds?
|
|
31
|
+
return true if distance_in_seconds < 60
|
|
32
|
+
|
|
33
|
+
distance_in_hours.zero? && distance_in_minutes.zero?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def distance_in_hours
|
|
37
|
+
((till - from).abs / 3600).floor
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def distance_in_minutes
|
|
41
|
+
(((till - from).abs % 3600) / 60).round
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def distance_in_seconds
|
|
45
|
+
(till - from).abs.round
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Cooldowns
|
|
6
|
+
module Strategies
|
|
7
|
+
class Exponential
|
|
8
|
+
include Calls
|
|
9
|
+
include ::Booth::Logging
|
|
10
|
+
|
|
11
|
+
option :scope
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
return limit_not_yet_reached! if seconds_to_wait.zero?
|
|
15
|
+
|
|
16
|
+
limit_reached!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def limit_reached!
|
|
22
|
+
log do
|
|
23
|
+
"Wait #{seconds_to_wait}/#{waiting_period} sec for #{number_of_incidents} incidents"
|
|
24
|
+
end
|
|
25
|
+
public_message = I18n.t('booth.try_again_cooldown', distance_of_time_until_cooldown:)
|
|
26
|
+
|
|
27
|
+
::Booth::Core::Cooldowns::Strategies::Result.failure(
|
|
28
|
+
public_message:,
|
|
29
|
+
attempts_left: 999_999,
|
|
30
|
+
cooldown_at:,
|
|
31
|
+
number_of_incidents:,
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def limit_not_yet_reached!
|
|
36
|
+
log { 'No need to wait' }
|
|
37
|
+
|
|
38
|
+
::Booth::Core::Cooldowns::Strategies::Result.success(
|
|
39
|
+
public_message: nil,
|
|
40
|
+
attempts_left: 999_999,
|
|
41
|
+
number_of_incidents:,
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Calculation Helpers
|
|
46
|
+
|
|
47
|
+
def cooldown_at
|
|
48
|
+
seconds_to_wait.from_now
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def seconds_to_wait
|
|
52
|
+
return 0 unless newest_timestamp
|
|
53
|
+
|
|
54
|
+
candidate = newest_timestamp.to_i + waiting_period - Time.current.to_i
|
|
55
|
+
return 0 if candidate.negative?
|
|
56
|
+
|
|
57
|
+
candidate
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def waiting_period
|
|
61
|
+
return 2.years if number_of_incidents > 9
|
|
62
|
+
|
|
63
|
+
# This effectively implies less than 10 attempts.
|
|
64
|
+
(5**number_of_incidents).seconds
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Queries
|
|
68
|
+
|
|
69
|
+
def number_of_incidents
|
|
70
|
+
@number_of_incidents ||= scope.count
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def newest_timestamp
|
|
74
|
+
return @newest_timestamp if defined? @newest_timestamp
|
|
75
|
+
|
|
76
|
+
@newest_timestamp = scope.maximum(:created_at)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Helpers
|
|
80
|
+
|
|
81
|
+
def distance_of_time_until_cooldown
|
|
82
|
+
::Booth::Core::Cooldowns::DistanceOfTime.call(from: Time.current, till: cooldown_at)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Cooldowns
|
|
6
|
+
module Strategies
|
|
7
|
+
class Global
|
|
8
|
+
include Calls
|
|
9
|
+
include ::Booth::Logging
|
|
10
|
+
|
|
11
|
+
option :scope
|
|
12
|
+
option :max_attempts
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
if number_of_incidents >= max_attempts
|
|
16
|
+
limit_reached!
|
|
17
|
+
else
|
|
18
|
+
limit_not_yet_reached!
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def limit_reached!
|
|
25
|
+
log { "Limited globally #{number_of_incidents}/#{max_attempts}" }
|
|
26
|
+
|
|
27
|
+
::Booth::Core::Cooldowns::Strategies::Result.failure(
|
|
28
|
+
public_message: I18n.t('booth.permanently_blocked'),
|
|
29
|
+
attempts_left:,
|
|
30
|
+
cooldown_at: nil,
|
|
31
|
+
number_of_incidents:,
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def limit_not_yet_reached!
|
|
36
|
+
log { "Not yet globally limited #{number_of_incidents}/#{max_attempts}" }
|
|
37
|
+
|
|
38
|
+
::Booth::Core::Cooldowns::Strategies::Result.success(
|
|
39
|
+
public_message:,
|
|
40
|
+
attempts_left:,
|
|
41
|
+
number_of_incidents:,
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def public_message
|
|
46
|
+
return if number_of_incidents.zero?
|
|
47
|
+
|
|
48
|
+
if attempts_left == 1
|
|
49
|
+
I18n.t 'booth.last_attempt'
|
|
50
|
+
else
|
|
51
|
+
I18n.t 'booth.attempts_left', attempts_left:
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def attempts_left
|
|
56
|
+
max_attempts - number_of_incidents
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def number_of_incidents
|
|
60
|
+
@number_of_incidents ||= scope.count
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Cooldowns
|
|
6
|
+
module Strategies
|
|
7
|
+
# All strategies quack the same way.
|
|
8
|
+
# They respond an immutable Tron Data object with additional information.
|
|
9
|
+
module Result
|
|
10
|
+
def self.failure(number_of_incidents:, public_message:, cooldown_at:, attempts_left:)
|
|
11
|
+
Tron.failure :hot, public_message:,
|
|
12
|
+
cooldown_at:,
|
|
13
|
+
attempts_left:,
|
|
14
|
+
number_of_incidents:
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.success(public_message:, number_of_incidents:, attempts_left:)
|
|
18
|
+
Tron.success :cool, number_of_incidents:,
|
|
19
|
+
cooldown_at: nil,
|
|
20
|
+
public_message:,
|
|
21
|
+
attempts_left:
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Credentials
|
|
6
|
+
class Create
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :domain
|
|
11
|
+
option :scope
|
|
12
|
+
option :username
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
if credential.save
|
|
16
|
+
log { "Successfully persisted a new Booth::Models::Credential record with ID #{credential.id.inspect}" }
|
|
17
|
+
Tron.success :credential_created, credential:
|
|
18
|
+
else
|
|
19
|
+
log { 'Could not persist a new Booth::Models::Credential record' }
|
|
20
|
+
Tron.failure :persistence_failed, error: credential.errors.to_a.to_sentence
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def credential
|
|
27
|
+
@credential ||= ::Booth::Models::Credential.new(domain:, username:, scope:)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|