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,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Sessions
|
|
6
|
+
# A Passport is an immutable representation of your current browser-session.
|
|
7
|
+
# For convenience, we add information about the Credential belonging to that session.
|
|
8
|
+
class ToPassport
|
|
9
|
+
include Calls
|
|
10
|
+
include ::Booth::Logging
|
|
11
|
+
|
|
12
|
+
param :session
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
::Booth::ToStruct.call(attributes)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
delegate :credential, to: :session, private: true
|
|
21
|
+
|
|
22
|
+
def attributes
|
|
23
|
+
{
|
|
24
|
+
username: credential.username,
|
|
25
|
+
session_id: session.id,
|
|
26
|
+
credential_id: credential.id,
|
|
27
|
+
incognito_credential_id: session.incognito_credential_id,
|
|
28
|
+
blocked: credential.blocked?,
|
|
29
|
+
revoked: session.revoked_at.present?,
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Webauth
|
|
6
|
+
class AuthenticationVerification
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :request
|
|
11
|
+
option :credential_id
|
|
12
|
+
option :challenge
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
if credential_id != authenticator.credential_id
|
|
16
|
+
raise 'this authenticator doesnt match the credential'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
log do
|
|
20
|
+
"Verifying using challenge #{challenge.inspect} and public key #{authenticator.public_key.inspect} and sign count #{authenticator.sign_count.inspect}"
|
|
21
|
+
end
|
|
22
|
+
webauth.verify(
|
|
23
|
+
challenge,
|
|
24
|
+
public_key: authenticator.public_key,
|
|
25
|
+
sign_count: authenticator.sign_count,
|
|
26
|
+
)
|
|
27
|
+
log { 'Response successfully verified' }
|
|
28
|
+
|
|
29
|
+
authenticator.update!(sign_count: webauth.sign_count)
|
|
30
|
+
sudo.webauth!
|
|
31
|
+
|
|
32
|
+
Tron.success :webauth_authentication_verification_successful,
|
|
33
|
+
credential: authenticator.credential,
|
|
34
|
+
public_json: {},
|
|
35
|
+
http_status: :created
|
|
36
|
+
rescue WebAuthn::SignCountVerificationError => e
|
|
37
|
+
log { "Response verification failed: #{e.message} (expected #{authenticator.sign_count})" }
|
|
38
|
+
# TODO: Audit
|
|
39
|
+
Tron.failure :webauth_failed, public_json: { public_message: 'Passkey Sign count mismatch.' },
|
|
40
|
+
public_message: "Verification failed: #{e.message}",
|
|
41
|
+
# expected_sign_count: authenticator.sign_count,
|
|
42
|
+
http_status: :unprocessable_entity
|
|
43
|
+
rescue WebAuthn::Error => e
|
|
44
|
+
log { "Response verification failed: #{e.message}" }
|
|
45
|
+
# TODO: Audit but don't throttle?
|
|
46
|
+
Tron.failure :webauth_failed, public_json: {},
|
|
47
|
+
public_message: "Verification failed: #{e.message}",
|
|
48
|
+
http_status: :unprocessable_entity
|
|
49
|
+
rescue RuntimeError => e
|
|
50
|
+
# This happens e.g. if the params[:id] does not match the params[:rawId]
|
|
51
|
+
raise
|
|
52
|
+
ensure
|
|
53
|
+
sudo.webauthn_challenge = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
delegate :sudo, to: :request
|
|
59
|
+
|
|
60
|
+
def webauth
|
|
61
|
+
::WebAuthn::Credential.from_get(request.params[:handshake], relying_party:)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def authenticator
|
|
65
|
+
device_id = ::WebAuthn.standard_encoder.encode(webauth.raw_id)
|
|
66
|
+
@authenticator ||= ::Booth::Models::Authenticator.where(credential_id:)
|
|
67
|
+
.find_by!(device_id:)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def relying_party
|
|
71
|
+
::Booth.config.relying_party_resolver.call(request:)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Webauth
|
|
6
|
+
class OptionsForCreate
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :webauthn_id
|
|
11
|
+
option :username
|
|
12
|
+
option :request
|
|
13
|
+
option :device_ids_to_exclude, default: -> {}
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
unless relying_party
|
|
17
|
+
log { "Could not resolve relying party for #{request.host}" }
|
|
18
|
+
return Tron.failure(:missing_relying_party, challenge: nil, as_json: nil,
|
|
19
|
+
relying_party_id: nil)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
options = ::WebAuthn::Credential.options_for_create(
|
|
23
|
+
user: {
|
|
24
|
+
id: webauthn_id,
|
|
25
|
+
name: username,
|
|
26
|
+
# Some browsers also support `display_name: "..."`
|
|
27
|
+
},
|
|
28
|
+
# Tell security key to also send its certificate as so called "attachment".
|
|
29
|
+
attestation: 'direct',
|
|
30
|
+
# Completely passwordless authentication should always require interaction/verification.
|
|
31
|
+
authenticator_selection: { user_verification: :required },
|
|
32
|
+
relying_party:,
|
|
33
|
+
|
|
34
|
+
# The advantage of excluding already registered devices is that we avoid duplicates.
|
|
35
|
+
# The disadvantage is, when the user manually resets the hardware device.
|
|
36
|
+
# Then the (now pristine) device cannot be used, because the orphan is still in the DB.
|
|
37
|
+
# In that case the user has to delete the orphan first, which seems okay.
|
|
38
|
+
exclude: device_ids_to_exclude,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
Tron.success(:webauthn_options_for_create, challenge: options.challenge,
|
|
42
|
+
as_json: options.as_json,
|
|
43
|
+
relying_party_id: options.relying_party&.id)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def relying_party
|
|
49
|
+
return @relying_party if defined?(@relying_party)
|
|
50
|
+
|
|
51
|
+
@relying_party = ::Booth.config.relying_party_resolver.call(request:)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Webauth
|
|
6
|
+
class OptionsForGet
|
|
7
|
+
include Calls
|
|
8
|
+
|
|
9
|
+
option :allowed_device_ids
|
|
10
|
+
option :request
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
raise 'what' unless relying_party
|
|
14
|
+
|
|
15
|
+
WebAuthn::Credential.options_for_get(
|
|
16
|
+
allow: allowed_device_ids,
|
|
17
|
+
user_verification: :required,
|
|
18
|
+
relying_party:,
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def relying_party
|
|
25
|
+
::Booth.config.relying_party_resolver.call(request:)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Webauth
|
|
6
|
+
# Queries the semi-official AAGUID database for passkey vendors.
|
|
7
|
+
class Provider
|
|
8
|
+
def self.find(aaguid)
|
|
9
|
+
attributes = all[aaguid.to_sym]
|
|
10
|
+
return unless attributes
|
|
11
|
+
|
|
12
|
+
attributes.merge!(aaguid:)
|
|
13
|
+
|
|
14
|
+
::Data.define(:aaguid, :name, :icon_dark, :icon_light).new(**attributes)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def self.all
|
|
20
|
+
@all ||= load_aaguids
|
|
21
|
+
end
|
|
22
|
+
private_class_method :all
|
|
23
|
+
|
|
24
|
+
def self.load_aaguids
|
|
25
|
+
# This file is downloaded via a rake task from
|
|
26
|
+
# https://github.com/passkeydeveloper/passkey-authenticator-aaguids
|
|
27
|
+
path = Pathname.new('../../../../data/combined_aaguid.json').expand_path(__dir__)
|
|
28
|
+
raise "Missing AAGUIDs file: #{path}" unless path.exist?
|
|
29
|
+
|
|
30
|
+
JSON.parse(path.read, symbolize_names: true)
|
|
31
|
+
end
|
|
32
|
+
private_class_method :load_aaguids
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Core
|
|
5
|
+
module Webauth
|
|
6
|
+
# Verifies the ajax-response of a hardware key to a previous challenge.
|
|
7
|
+
class RegistrationVerification
|
|
8
|
+
include Calls
|
|
9
|
+
include ::Booth::Logging
|
|
10
|
+
|
|
11
|
+
option :credential_id
|
|
12
|
+
option :challenge
|
|
13
|
+
option :handshake
|
|
14
|
+
option :request
|
|
15
|
+
|
|
16
|
+
def call
|
|
17
|
+
do_verify_response
|
|
18
|
+
.on_success { do_return_attributes }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def do_verify_response
|
|
24
|
+
log { "Verifying challenge #{challenge.inspect} using handshake #{handshake}" }
|
|
25
|
+
webauth.verify(challenge)
|
|
26
|
+
log { 'Response successfully verified' }
|
|
27
|
+
|
|
28
|
+
Tron.success :webauth_registration_verification_successful
|
|
29
|
+
rescue WebAuthn::AttestationStatementVerificationError => e
|
|
30
|
+
# Only happens when `::WebAuthn.config.verify_attestation_statement = true`
|
|
31
|
+
log { "Attestation Verification failed - #{e.message}" }
|
|
32
|
+
Tron.failure :attestation_verification_failed,
|
|
33
|
+
public_json: { public_message: 'Attestation Statement Verification failed' },
|
|
34
|
+
http_status: :bad_request
|
|
35
|
+
|
|
36
|
+
# rescue WebAuthn::SignCountVerificationError => e
|
|
37
|
+
# At Registration this should never happen.
|
|
38
|
+
# Because the sign_counter will always be 0 (or 1?).
|
|
39
|
+
rescue WebAuthn::OriginVerificationError => e
|
|
40
|
+
log { 'Request must come from allowed origin' }
|
|
41
|
+
Tron.failure :origin_verification_failed,
|
|
42
|
+
http_status: :unprocessable_entity,
|
|
43
|
+
public_json: {
|
|
44
|
+
public_message: "The origin hostname/port could not be verified (#{e.message})"
|
|
45
|
+
}
|
|
46
|
+
rescue WebAuthn::Error => e
|
|
47
|
+
log { "Webauth Handshake failed: #{e.message}" }
|
|
48
|
+
Tron.failure :invalid_challenge_response
|
|
49
|
+
# TODO: Audit but don't throttle?
|
|
50
|
+
Tron.failure :webauth_failed,
|
|
51
|
+
http_status: :unprocessable_entity,
|
|
52
|
+
public_json: {
|
|
53
|
+
public_message: "Verification failed: #{e.message}"
|
|
54
|
+
}
|
|
55
|
+
rescue RuntimeError => e
|
|
56
|
+
# This happens e.g. if the params[:id] does not match the params[:rawId]
|
|
57
|
+
log { "Registration Verification failed - #{e.class} #{e.message}" }
|
|
58
|
+
Tron.failure(:registration_verification_failed, http_status: :bad_request,
|
|
59
|
+
public_json: { public_message: e.message })
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def do_return_attributes
|
|
63
|
+
Tron.success :registration_verification_successful,
|
|
64
|
+
device_id:,
|
|
65
|
+
public_key: webauth.public_key,
|
|
66
|
+
attachment: webauth.authenticator_attachment,
|
|
67
|
+
sign_count: webauth.sign_count,
|
|
68
|
+
aaguid:,
|
|
69
|
+
issuer:,
|
|
70
|
+
confirmed_at: Time.current
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def aaguid
|
|
74
|
+
webauth.response.attestation_object.aaguid
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def device_id
|
|
78
|
+
::WebAuthn.standard_encoder.encode(webauth.raw_id.to_s)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def issuer
|
|
82
|
+
webauth.response
|
|
83
|
+
.attestation_object
|
|
84
|
+
.attestation_statement
|
|
85
|
+
.attestation_certificate
|
|
86
|
+
&.subject
|
|
87
|
+
&.to_utf8
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def webauth
|
|
91
|
+
@webauth ||= ::WebAuthn::Credential.from_create(handshake, relying_party:)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def relying_party
|
|
95
|
+
::Booth.config.relying_party_resolver.call(request:)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
# Public read-only Model you can call in your Rails app.
|
|
5
|
+
#
|
|
6
|
+
# We expose read-only Credentials without associations for DB querying and joins
|
|
7
|
+
# that the Rails developer might like to perform. E.g. Customer.joins(:credential)
|
|
8
|
+
# This is the only exception, other records will be queried through Adminland#some_method
|
|
9
|
+
#
|
|
10
|
+
# You can join this in your models the usual way:
|
|
11
|
+
#
|
|
12
|
+
# class Customer < ApplicationRecord
|
|
13
|
+
# belongs_to :credential, class_name: '::Booth::Credential'
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# You can even subclass it:
|
|
17
|
+
#
|
|
18
|
+
# class Credential < Booth::Credential
|
|
19
|
+
# has_one :customer, dependent: :nullify
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# So that you can run join queries:
|
|
23
|
+
#
|
|
24
|
+
# Credential.where(domain: 'example.com', scope: :community).where.missing(:customer)
|
|
25
|
+
#
|
|
26
|
+
# You may also reference this table in migrations:
|
|
27
|
+
#
|
|
28
|
+
# add_foreign_key :customers, :booth_credentials, column: :credential_id, on_delete: :nullify
|
|
29
|
+
#
|
|
30
|
+
class Credential < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
|
|
31
|
+
self.table_name = 'booth_credentials'
|
|
32
|
+
|
|
33
|
+
after_initialize :readonly!
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/booth/engine.rb
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
4
|
+
# The Booth Engine you can use in your Rails app.
|
|
2
5
|
class Engine < ::Rails::Engine
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
config.autoload_paths << root.join('lib')
|
|
7
|
+
|
|
8
|
+
initializer 'booth.importmap', before: 'importmap' do |app|
|
|
9
|
+
app.config.importmap.paths << Engine.root.join('config/importmap.rb')
|
|
10
|
+
# Watch JS changes in development
|
|
11
|
+
app.config.importmap.cache_sweepers << Engine.root.join('app/assets/javascripts')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
initializer 'booth.assets' do |app|
|
|
15
|
+
app.config.assets.paths << Engine.root.join('app/javascript')
|
|
5
16
|
end
|
|
6
17
|
|
|
7
18
|
initializer 'booth.insert_warden_middleware' do |app|
|
|
8
19
|
app.config.middleware.insert_after ::ActionDispatch::Flash, ::Warden::Manager do |manager|
|
|
9
20
|
manager.intercept_401 = false
|
|
10
|
-
manager.serialize_into_session { ::Booth::Hooks::SerializeIntoSession.call(
|
|
11
|
-
manager.serialize_from_session { ::Booth::Hooks::SerializeFromSession.call(
|
|
21
|
+
manager.serialize_into_session { ::Booth::Hooks::SerializeIntoSession.call(it) }
|
|
22
|
+
manager.serialize_from_session { ::Booth::Hooks::SerializeFromSession.call(it) }
|
|
12
23
|
end
|
|
13
24
|
end
|
|
14
25
|
|
data/lib/booth/errors.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Hooks
|
|
5
|
+
# Once Warden fetched the session from DB, let's check it for authorization.
|
|
3
6
|
class AfterFetch
|
|
4
|
-
include
|
|
7
|
+
include Calls
|
|
5
8
|
include ::Booth::Logging
|
|
6
9
|
|
|
7
10
|
option :passport
|
|
@@ -9,11 +12,16 @@ module Booth
|
|
|
9
12
|
option :options
|
|
10
13
|
|
|
11
14
|
def call
|
|
12
|
-
if passport.
|
|
13
|
-
|
|
15
|
+
if passport.blocked
|
|
16
|
+
log { 'Your credential is blocked. Logging you out.' }
|
|
17
|
+
request.authentication.logout
|
|
18
|
+
|
|
19
|
+
elsif passport.revoked
|
|
20
|
+
log { "Your session in scope #{scope.inspect} was revoked. Logging you out." }
|
|
14
21
|
request.authentication.logout
|
|
22
|
+
|
|
15
23
|
else
|
|
16
|
-
|
|
24
|
+
log { "Registering activity of legitimate session in scope #{scope.inspect} with IP #{request.ip}..." }
|
|
17
25
|
register_activity
|
|
18
26
|
end
|
|
19
27
|
|
|
@@ -23,7 +31,7 @@ module Booth
|
|
|
23
31
|
private
|
|
24
32
|
|
|
25
33
|
def register_activity
|
|
26
|
-
::Booth::Models::Session.where(id: passport.
|
|
34
|
+
::Booth::Models::Session.where(id: passport.session_id).update_all(
|
|
27
35
|
['activity_at = ?, ' \
|
|
28
36
|
'agent = ?, ' \
|
|
29
37
|
'location = ?, ' \
|
|
@@ -37,7 +45,7 @@ module Booth
|
|
|
37
45
|
request.ip,
|
|
38
46
|
request.location,
|
|
39
47
|
request.ip,
|
|
40
|
-
Time.current.to_i.to_s]
|
|
48
|
+
Time.current.to_i.to_s],
|
|
41
49
|
)
|
|
42
50
|
end
|
|
43
51
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Hooks
|
|
3
5
|
class BeforeLogout
|
|
4
|
-
include
|
|
6
|
+
include Calls
|
|
5
7
|
include ::Booth::Logging
|
|
6
8
|
|
|
7
9
|
option :passport
|
|
@@ -11,9 +13,9 @@ module Booth
|
|
|
11
13
|
def call
|
|
12
14
|
return unless passport # Attempting to logout when already logged out.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
log { "Revoking Session #{passport.session_id} in scope #{scope.inspect} because of logout" }
|
|
15
17
|
|
|
16
|
-
::Booth::Models::Session.where(id: passport.
|
|
18
|
+
::Booth::Models::Session.where(id: passport.session_id)
|
|
17
19
|
.update_all(revoked_at: Time.current, revoke_reason: :logout)
|
|
18
20
|
|
|
19
21
|
nil
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Hooks
|
|
5
|
+
# Convert what is in the cookie to a session record from the DB.
|
|
3
6
|
class SerializeFromSession
|
|
4
|
-
include
|
|
7
|
+
include Calls
|
|
5
8
|
include ::Booth::Logging
|
|
6
9
|
|
|
7
10
|
param :session_id
|
|
@@ -9,15 +12,20 @@ module Booth
|
|
|
9
12
|
def call
|
|
10
13
|
::Booth::Syntaxes::Uuid.call(session_id, raise_if_invalid: true)
|
|
11
14
|
|
|
12
|
-
session = ::Booth::Models::Session.active_scope
|
|
15
|
+
session = ::Booth::Models::Session.active_scope
|
|
16
|
+
.includes_scope
|
|
17
|
+
.find_by(id: session_id)
|
|
13
18
|
|
|
14
19
|
unless session
|
|
15
|
-
|
|
20
|
+
log { "Session ID #{session_id.inspect} stored in cookie doesn't exist in database" }
|
|
21
|
+
|
|
22
|
+
# p ::Booth::Models::Session.find_by(id: session_id)
|
|
23
|
+
|
|
16
24
|
return
|
|
17
25
|
end
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
::Booth::Sessions::ToPassport.call(session)
|
|
27
|
+
log { "Deserializing DB Session #{session_id.inspect} information into Warden cookie..." }
|
|
28
|
+
::Booth::Core::Sessions::ToPassport.call(session)
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
end
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Hooks
|
|
5
|
+
# Persist an authenticated session in the cookie.
|
|
3
6
|
class SerializeIntoSession
|
|
4
|
-
include
|
|
7
|
+
include Calls
|
|
5
8
|
|
|
6
9
|
param :passport
|
|
7
10
|
|
|
8
11
|
def call
|
|
9
|
-
# This is the ID of the `Booth::Models::Session
|
|
10
|
-
passport.
|
|
12
|
+
# This is the ID of the `Booth::Models::Session` record.
|
|
13
|
+
passport.session_id
|
|
11
14
|
end
|
|
12
15
|
end
|
|
13
16
|
end
|
data/lib/booth/logging.rb
CHANGED
|
@@ -1,59 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Logging
|
|
3
5
|
extend ActiveSupport::Concern
|
|
4
6
|
|
|
5
|
-
# TODO: Implement only generic `log` method to avoid cluttering the Object where this was included.
|
|
6
|
-
# We only use `debug` anyway.
|
|
7
7
|
class_methods do
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def info(&)
|
|
13
|
-
_logger.info(&)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def warn(&)
|
|
17
|
-
_logger.warn(&)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def error(&)
|
|
21
|
-
_logger.error(&)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def fatal(&)
|
|
25
|
-
_logger.fatal(&)
|
|
8
|
+
def log(&)
|
|
9
|
+
::Booth.config.logger&.debug(to_s, &)
|
|
26
10
|
end
|
|
27
11
|
|
|
28
|
-
def
|
|
29
|
-
|
|
12
|
+
def emit(event_name, data = {})
|
|
13
|
+
# See https://github.com/rails/rails/blob/main/activesupport/lib/active_support/event_reporter.rb
|
|
14
|
+
::Rails.event.notify("booth.#{event_name}", data, caller_depth: 2)
|
|
15
|
+
nil
|
|
30
16
|
end
|
|
31
17
|
end
|
|
32
18
|
|
|
33
19
|
private
|
|
34
20
|
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def info(&)
|
|
40
|
-
_logger.info(&)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def warn(&)
|
|
44
|
-
_logger.warn(&)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def error(&)
|
|
48
|
-
_logger.error(&)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def fatal(&)
|
|
52
|
-
_logger.fatal(&)
|
|
21
|
+
def log(&)
|
|
22
|
+
::Booth.config.logger&.debug(self.class.to_s, &)
|
|
53
23
|
end
|
|
54
24
|
|
|
55
|
-
def
|
|
56
|
-
|
|
25
|
+
def emit(event_name, data = {})
|
|
26
|
+
::Rails.event.notify("booth.#{event_name}", data, caller_depth: 2)
|
|
27
|
+
nil
|
|
57
28
|
end
|
|
58
29
|
end
|
|
59
30
|
end
|
data/lib/booth/models/audit.rb
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Booth
|
|
2
4
|
module Models
|
|
5
|
+
# An event log.
|
|
3
6
|
class Audit < ::Booth::Models::ApplicationRecord
|
|
4
7
|
self.table_name = 'booth_audits'
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
logout: 'logout',
|
|
13
|
-
queried_unknown_username: 'queried_unknown_username',
|
|
14
|
-
requested_password_reset: 'requested_password_reset' },
|
|
15
|
-
_prefix: true
|
|
9
|
+
# changed_tenant (payload from: to:)
|
|
10
|
+
enum :event, %i[
|
|
11
|
+
completed_onboarding
|
|
12
|
+
logout
|
|
13
|
+
registered
|
|
14
|
+
].index_with(&:to_s), prefix: true
|
|
16
15
|
|
|
17
|
-
belongs_to :credential,
|
|
16
|
+
belongs_to :credential, optional: true
|
|
18
17
|
|
|
19
18
|
validates :ip, :event, presence: true
|
|
20
19
|
|