booth 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE.md +22 -0
- data/README.md +372 -0
- data/app/assets/config/booth_manifest.js +15 -0
- data/app/assets/images/booth/browsers/README.md +2 -0
- data/app/assets/images/booth/browsers/chrome.svg +1 -0
- data/app/assets/images/booth/browsers/edge.svg +1 -0
- data/app/assets/images/booth/browsers/firefox.svg +1 -0
- data/app/assets/images/booth/browsers/internet_explorer.svg +1 -0
- data/app/assets/images/booth/browsers/opera.svg +1 -0
- data/app/assets/images/booth/browsers/safari.svg +1 -0
- data/app/assets/images/booth/browsers/unknown.svg +1 -0
- data/app/assets/images/booth/platforms/README.md +2 -0
- data/app/assets/images/booth/platforms/android.svg +6 -0
- data/app/assets/images/booth/platforms/apple.svg +6 -0
- data/app/assets/images/booth/platforms/linux.svg +6 -0
- data/app/assets/images/booth/platforms/unknown.svg +1 -0
- data/app/assets/images/booth/platforms/windows.svg +6 -0
- data/app/assets/javascripts/booth/all.js +162 -0
- data/app/assets/javascripts/booth/all.js.map +1 -0
- data/app/assets/javascripts/booth/booth.ts +194 -0
- data/app/assets/javascripts/booth/webauthn-json.ts +99 -0
- data/config/locales/de.yml +84 -0
- data/config/locales/en.yml +79 -0
- data/lib/booth/adminland/credentials/create.rb +30 -0
- data/lib/booth/adminland/onboardings/create.rb +63 -0
- data/lib/booth/adminland/onboardings/destroy.rb +50 -0
- data/lib/booth/adminland/onboardings/find.rb +93 -0
- data/lib/booth/adminland/onboardings/index.rb +23 -0
- data/lib/booth/adminland/periodic_cleanup.rb +11 -0
- data/lib/booth/adminland/recoveries/consume.rb +70 -0
- data/lib/booth/adminland.rb +48 -0
- data/lib/booth/audits/register/added_otp.rb +22 -0
- data/lib/booth/audits/register/changed_otp.rb +22 -0
- data/lib/booth/audits/register/completed_onboarding.rb +22 -0
- data/lib/booth/audits/register/correct_otp.rb +42 -0
- data/lib/booth/audits/register/correct_password.rb +43 -0
- data/lib/booth/audits/register/logout.rb +22 -0
- data/lib/booth/audits/register/requested_password_reset.rb +22 -0
- data/lib/booth/audits/register/wrong_otp.rb +22 -0
- data/lib/booth/audits/register/wrong_password.rb +25 -0
- data/lib/booth/authenticators/confirm.rb +34 -0
- data/lib/booth/authenticators/credential_mode_after_confirmation.rb +25 -0
- data/lib/booth/authenticators/step.rb +19 -0
- data/lib/booth/concerns/action.rb +58 -0
- data/lib/booth/concerns/transition.rb +17 -0
- data/lib/booth/configuration.rb +116 -0
- data/lib/booth/configure.rb +37 -0
- data/lib/booth/contests/get.rb +36 -0
- data/lib/booth/contests/respond.rb +78 -0
- data/lib/booth/contests/set_for_login.rb +28 -0
- data/lib/booth/cooldowns/distance_of_time.rb +46 -0
- data/lib/booth/cooldowns/otp.rb +22 -0
- data/lib/booth/cooldowns/password.rb +44 -0
- data/lib/booth/cooldowns/password_reset.rb +24 -0
- data/lib/booth/cooldowns/strategies/exponential.rb +82 -0
- data/lib/booth/cooldowns/strategies/global.rb +62 -0
- data/lib/booth/cooldowns/strategies/result.rb +22 -0
- data/lib/booth/credentials/create.rb +28 -0
- data/lib/booth/credentials/create_with_onboarding.rb +26 -0
- data/lib/booth/credentials/find_by_username.rb +45 -0
- data/lib/booth/credentials/mode.rb +69 -0
- data/lib/booth/credentials/modes/otp_addable.rb +23 -0
- data/lib/booth/credentials/modes/otp_changeable.rb +23 -0
- data/lib/booth/credentials/modes/otp_manageable.rb +17 -0
- data/lib/booth/credentials/modes/otp_removable.rb +23 -0
- data/lib/booth/credentials/modes/password_addable.rb +29 -0
- data/lib/booth/credentials/modes/password_changeable.rb +31 -0
- data/lib/booth/credentials/modes/password_manageable.rb +17 -0
- data/lib/booth/credentials/modes/password_removable.rb +24 -0
- data/lib/booth/credentials/modes/password_removal_requires_user_verifiable_webauth.rb +16 -0
- data/lib/booth/credentials/modes/webauth_addable.rb +26 -0
- data/lib/booth/credentials/modes/webauth_manageable.rb +16 -0
- data/lib/booth/credentials/modes/webauth_removable.rb +25 -0
- data/lib/booth/credentials/otp_authentication.rb +59 -0
- data/lib/booth/credentials/password_authentication.rb +72 -0
- data/lib/booth/credentials/webauth_challenge.rb +28 -0
- data/lib/booth/engine.rb +25 -0
- data/lib/booth/errors.rb +86 -0
- data/lib/booth/geolocation.rb +20 -0
- data/lib/booth/hooks/after_fetch.rb +54 -0
- data/lib/booth/hooks/before_logout.rb +29 -0
- data/lib/booth/hooks/serialize_from_session.rb +24 -0
- data/lib/booth/hooks/serialize_into_session.rb +14 -0
- data/lib/booth/logger.rb +41 -0
- data/lib/booth/logging.rb +59 -0
- data/lib/booth/method_object.rb +73 -0
- data/lib/booth/mode.rb +22 -0
- data/lib/booth/models/application_record.rb +7 -0
- data/lib/booth/models/audit.rb +24 -0
- data/lib/booth/models/authenticator.rb +45 -0
- data/lib/booth/models/concerns/modeable.rb +50 -0
- data/lib/booth/models/concerns/otpable.rb +37 -0
- data/lib/booth/models/concerns/passwordable.rb +58 -0
- data/lib/booth/models/contest.rb +55 -0
- data/lib/booth/models/contests/scopes/recently_created.rb +23 -0
- data/lib/booth/models/contests/scopes/recently_responded.rb +32 -0
- data/lib/booth/models/credential.rb +61 -0
- data/lib/booth/models/onboarding.rb +61 -0
- data/lib/booth/models/password_reset.rb +41 -0
- data/lib/booth/models/recovery.rb +32 -0
- data/lib/booth/models/registration.rb +10 -0
- data/lib/booth/models/session.rb +47 -0
- data/lib/booth/models/user_agent.rb +50 -0
- data/lib/booth/modes/base.rb +25 -0
- data/lib/booth/modes/username_and_password.rb +7 -0
- data/lib/booth/modes/username_and_webauth.rb +7 -0
- data/lib/booth/modes/username_password_and_otp.rb +7 -0
- data/lib/booth/modes/username_password_and_webauth.rb +7 -0
- data/lib/booth/onboardings/find.rb +35 -0
- data/lib/booth/onboardings/propagate_to_credential.rb +63 -0
- data/lib/booth/onboardings/step.rb +68 -0
- data/lib/booth/password_resets/create.rb +57 -0
- data/lib/booth/password_resets/find.rb +36 -0
- data/lib/booth/password_resets/propagate_to_credential.rb +36 -0
- data/lib/booth/password_resets/step.rb +18 -0
- data/lib/booth/recoveries/create.rb +45 -0
- data/lib/booth/request.rb +106 -0
- data/lib/booth/requests/agent.rb +14 -0
- data/lib/booth/requests/authentication.rb +47 -0
- data/lib/booth/requests/ip.rb +28 -0
- data/lib/booth/requests/return_path.rb +34 -0
- data/lib/booth/requests/session.rb +106 -0
- data/lib/booth/requests/storage.rb +62 -0
- data/lib/booth/requests/storages/login.rb +108 -0
- data/lib/booth/requests/storages/otp.rb +54 -0
- data/lib/booth/requests/storages/password.rb +49 -0
- data/lib/booth/requests/storages/password_reset.rb +35 -0
- data/lib/booth/requests/storages/recovery.rb +35 -0
- data/lib/booth/requests/storages/registration.rb +27 -0
- data/lib/booth/requests/storages/webauth.rb +38 -0
- data/lib/booth/requests/sudo.rb +110 -0
- data/lib/booth/routes/userland.rb +80 -0
- data/lib/booth/sessions/create_and_login.rb +46 -0
- data/lib/booth/sessions/historical_locations.rb +18 -0
- data/lib/booth/sessions/index.rb +59 -0
- data/lib/booth/sessions/revoke.rb +51 -0
- data/lib/booth/sessions/revoke_all_others.rb +43 -0
- data/lib/booth/sessions/to_passport.rb +51 -0
- data/lib/booth/syntaxes/contest_code.rb +58 -0
- data/lib/booth/syntaxes/email.rb +97 -0
- data/lib/booth/syntaxes/ip.rb +37 -0
- data/lib/booth/syntaxes/otp.rb +57 -0
- data/lib/booth/syntaxes/scope.rb +21 -0
- data/lib/booth/syntaxes/scope_comparison.rb +28 -0
- data/lib/booth/syntaxes/secret_key.rb +64 -0
- data/lib/booth/syntaxes/username.rb +85 -0
- data/lib/booth/syntaxes/uuid.rb +23 -0
- data/lib/booth/test/helpers.rb +63 -0
- data/lib/booth/test/support/assert_all_partials_were_covered.rb +63 -0
- data/lib/booth/test/support/assert_logged_in.rb +49 -0
- data/lib/booth/test/support/assert_logged_out.rb +30 -0
- data/lib/booth/test/support/assert_partial.rb +29 -0
- data/lib/booth/test/support/force_login.rb +26 -0
- data/lib/booth/test/support/get_session_value.rb +35 -0
- data/lib/booth/test/support/otp_code_from_session.rb +30 -0
- data/lib/booth/test/support/soft_reset_session.rb +22 -0
- data/lib/booth/test/userland/logins/missing_authenticators.rb +72 -0
- data/lib/booth/test/userland/logins/missing_onboarding.rb +35 -0
- data/lib/booth/test/userland/logins/username_and_password.rb +40 -0
- data/lib/booth/test/userland/logins/username_and_webauth.rb +75 -0
- data/lib/booth/test/userland/logins/username_password_and_otp.rb +45 -0
- data/lib/booth/test/userland/logins/username_password_and_webauth.rb +86 -0
- data/lib/booth/test/userland/onboardings/already_logged_in.rb +64 -0
- data/lib/booth/test/userland/onboardings/otp.rb +63 -0
- data/lib/booth/test/userland/onboardings/password.rb +49 -0
- data/lib/booth/test/userland/onboardings/timeout.rb +47 -0
- data/lib/booth/test/userland/otps/manage.rb +86 -0
- data/lib/booth/test/userland/password_resets/reset.rb +102 -0
- data/lib/booth/test/userland.rb +38 -0
- data/lib/booth/test/webauthn/disable.rb +17 -0
- data/lib/booth/test/webauthn/enable.rb +19 -0
- data/lib/booth/test/webauthn/virtual_authenticators/create.rb +38 -0
- data/lib/booth/test/webauthn/virtual_authenticators/destroy.rb +20 -0
- data/lib/booth/test.rb +53 -0
- data/lib/booth/to_struct.rb +11 -0
- data/lib/booth/userland/extract_flash_messages.rb +35 -0
- data/lib/booth/userland/logins/create.rb +28 -0
- data/lib/booth/userland/logins/destroy.rb +37 -0
- data/lib/booth/userland/logins/new.rb +70 -0
- data/lib/booth/userland/logins/transitions/create/choose_username.rb +41 -0
- data/lib/booth/userland/logins/transitions/create/enter_otp.rb +70 -0
- data/lib/booth/userland/logins/transitions/create/skip_remotes.rb +24 -0
- data/lib/booth/userland/logins/transitions/create/verify_password.rb +70 -0
- data/lib/booth/userland/logins/transitions/create/webauth_authentication_initiation.rb +55 -0
- data/lib/booth/userland/logins/transitions/create/webauth_authentication_verification.rb +80 -0
- data/lib/booth/userland/logins/transitions/new/already_logged_in.rb +21 -0
- data/lib/booth/userland/logins/transitions/new/fallible.rb +27 -0
- data/lib/booth/userland/logins/transitions/new/mode_first_time.rb +20 -0
- data/lib/booth/userland/logins/transitions/new/mode_username_and_password.rb +20 -0
- data/lib/booth/userland/logins/transitions/new/mode_username_and_webauth.rb +26 -0
- data/lib/booth/userland/logins/transitions/new/mode_username_password_and_otp.rb +24 -0
- data/lib/booth/userland/logins/transitions/new/mode_username_password_and_webauth.rb +24 -0
- data/lib/booth/userland/logins/transitions/new/no_username_chosen.rb +19 -0
- data/lib/booth/userland/logins/transitions/new/remote_session_available.rb +52 -0
- data/lib/booth/userland/logins/transitions/new/timed_out.rb +25 -0
- data/lib/booth/userland/onboardings/show.rb +74 -0
- data/lib/booth/userland/onboardings/transitions/update/choose_mode.rb +58 -0
- data/lib/booth/userland/onboardings/transitions/update/choose_password.rb +41 -0
- data/lib/booth/userland/onboardings/transitions/update/choose_webauth_nickname.rb +50 -0
- data/lib/booth/userland/onboardings/transitions/update/confirm_otp.rb +58 -0
- data/lib/booth/userland/onboardings/transitions/update/confirm_password.rb +49 -0
- data/lib/booth/userland/onboardings/transitions/update/register_otp.rb +31 -0
- data/lib/booth/userland/onboardings/transitions/update/reset_otp.rb +40 -0
- data/lib/booth/userland/onboardings/transitions/update/reset_password.rb +35 -0
- data/lib/booth/userland/onboardings/transitions/update/reset_webauth.rb +46 -0
- data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_initiation.rb +40 -0
- data/lib/booth/userland/onboardings/transitions/update/webauth_authentication_verification.rb +59 -0
- data/lib/booth/userland/onboardings/transitions/update/webauth_registration_initiation.rb +46 -0
- data/lib/booth/userland/onboardings/transitions/update/webauth_registration_verification.rb +56 -0
- data/lib/booth/userland/onboardings/update.rb +68 -0
- data/lib/booth/userland/otps/destroy.rb +42 -0
- data/lib/booth/userland/otps/edit.rb +72 -0
- data/lib/booth/userland/otps/guards/manageable.rb +21 -0
- data/lib/booth/userland/otps/guards/sudo.rb +23 -0
- data/lib/booth/userland/otps/show.rb +36 -0
- data/lib/booth/userland/otps/sudo.rb +51 -0
- data/lib/booth/userland/otps/transitions/update/confirm.rb +84 -0
- data/lib/booth/userland/otps/transitions/update/register.rb +40 -0
- data/lib/booth/userland/otps/transitions/update/reset.rb +31 -0
- data/lib/booth/userland/otps/update.rb +34 -0
- data/lib/booth/userland/password_resets/create.rb +73 -0
- data/lib/booth/userland/password_resets/guards/logged_out.rb +21 -0
- data/lib/booth/userland/password_resets/new.rb +57 -0
- data/lib/booth/userland/password_resets/show.rb +77 -0
- data/lib/booth/userland/password_resets/transitions/update/choose_password.rb +48 -0
- data/lib/booth/userland/password_resets/transitions/update/confirm_password.rb +54 -0
- data/lib/booth/userland/password_resets/transitions/update/reset_password.rb +29 -0
- data/lib/booth/userland/password_resets/update.rb +65 -0
- data/lib/booth/userland/passwords/destroy.rb +41 -0
- data/lib/booth/userland/passwords/edit.rb +54 -0
- data/lib/booth/userland/passwords/guards/manageable.rb +21 -0
- data/lib/booth/userland/passwords/guards/removable.rb +21 -0
- data/lib/booth/userland/passwords/guards/sudo.rb +21 -0
- data/lib/booth/userland/passwords/remove.rb +34 -0
- data/lib/booth/userland/passwords/show.rb +32 -0
- data/lib/booth/userland/passwords/sudo.rb +55 -0
- data/lib/booth/userland/passwords/transitions/remove/step.rb +27 -0
- data/lib/booth/userland/passwords/transitions/update/choose_password.rb +62 -0
- data/lib/booth/userland/passwords/transitions/update/confirm_password.rb +82 -0
- data/lib/booth/userland/passwords/update.rb +33 -0
- data/lib/booth/userland/personal_contests/show.rb +60 -0
- data/lib/booth/userland/personal_contests/update.rb +37 -0
- data/lib/booth/userland/recoveries/create.rb +48 -0
- data/lib/booth/userland/recoveries/new.rb +35 -0
- data/lib/booth/userland/registrations/create.rb +56 -0
- data/lib/booth/userland/registrations/new.rb +39 -0
- data/lib/booth/userland/sessions/destroy_one_or_other.rb +41 -0
- data/lib/booth/userland/sessions/index.rb +27 -0
- data/lib/booth/userland/sessions/show.rb +31 -0
- data/lib/booth/userland/sessions/transitions/destroy/enter_password.rb +50 -0
- data/lib/booth/userland/sessions/transitions/destroy/enter_webauth.rb +56 -0
- data/lib/booth/userland/sessions/transitions/destroy/verify_password.rb +83 -0
- data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_initiation.rb +38 -0
- data/lib/booth/userland/sessions/transitions/destroy/webauth_authentication_verification.rb +61 -0
- data/lib/booth/userland/sessions/transitions/show/enter_webauth.rb +56 -0
- data/lib/booth/userland/webauths/create.rb +83 -0
- data/lib/booth/userland/webauths/destroy.rb +60 -0
- data/lib/booth/userland/webauths/guards/manageable.rb +21 -0
- data/lib/booth/userland/webauths/guards/sudo.rb +22 -0
- data/lib/booth/userland/webauths/index.rb +43 -0
- data/lib/booth/userland/webauths/new.rb +70 -0
- data/lib/booth/userland/webauths/sudo.rb +25 -0
- data/lib/booth/userland/webauths/transitions/create/authentication_initiation.rb +52 -0
- data/lib/booth/userland/webauths/transitions/create/authentication_verification.rb +64 -0
- data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +50 -0
- data/lib/booth/userland/webauths/transitions/create/registration_initiation.rb +61 -0
- data/lib/booth/userland/webauths/transitions/create/registration_verification.rb +68 -0
- data/lib/booth/userland/webauths/transitions/create/reset.rb +36 -0
- data/lib/booth/userland/webauths/transitions/new/step.rb +23 -0
- data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +47 -0
- data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +34 -0
- data/lib/booth/userland.rb +192 -0
- data/lib/booth/version.rb +3 -0
- data/lib/booth/webauth/authentication_verification.rb +68 -0
- data/lib/booth/webauth/demand_user_verification.rb +29 -0
- data/lib/booth/webauth/options_for_create.rb +46 -0
- data/lib/booth/webauth/options_for_get.rb +29 -0
- data/lib/booth.rb +267 -0
- data/lib/generators/booth/migration/migration_generator.rb +25 -0
- data/lib/generators/booth/migration/templates/add_credential_to_users.erb +18 -0
- data/lib/generators/booth/migration/templates/create_booth_mode_types.erb +20 -0
- data/lib/generators/booth/migration/templates/create_booth_tables.erb +135 -0
- metadata +861 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
class Destroy
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_delete!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
request.must_be_logged_in!
|
|
11
|
+
request.sudo.guard_with_otp { return _1 }
|
|
12
|
+
|
|
13
|
+
do_require_eligible_credential
|
|
14
|
+
.on_success { do_destroy }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def do_require_eligible_credential
|
|
20
|
+
return Tron.success :can_remove_otp if ::Booth::Credentials::Modes::OtpRemovable.call(credential)
|
|
21
|
+
|
|
22
|
+
Tron.failure :credential_not_otpable, public_message: I18n.t('booth.otp_not_eligible')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def do_destroy
|
|
26
|
+
if credential.mode_username_and_password!
|
|
27
|
+
credential.otp_regenerate_secret
|
|
28
|
+
credential.save # Not critical if this one fails
|
|
29
|
+
|
|
30
|
+
return Tron.success :otp_removed, public_message: I18n.t('booth.otp_removed')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Tron.failure :otp_removal_failed
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def credential
|
|
37
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
class Edit
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_get!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
request.must_be_logged_in!
|
|
11
|
+
|
|
12
|
+
::Booth::Userland::Otps::Guards::Manageable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Otps::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_require_eligible_credential
|
|
16
|
+
# .on_success { do_clear_previous_editing }
|
|
17
|
+
.on_success { do_ensure_temporary_secret_key }
|
|
18
|
+
.on_success { do_reveal_otp_secret }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def do_require_eligible_credential
|
|
24
|
+
return Tron.success :can_add_otp if ::Booth::Credentials::Modes::OtpAddable.call(credential)
|
|
25
|
+
return Tron.success :can_change_otp if ::Booth::Credentials::Modes::OtpChangeable.call(credential)
|
|
26
|
+
|
|
27
|
+
Tron.failure :credential_not_otpable, public_message: I18n.t('booth.otp_not_eligible')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Hm, tests failed with this.
|
|
31
|
+
# def do_clear_previous_editing
|
|
32
|
+
# return Tron.success :no_previous_editing unless storage.secret_key_recently_changed?
|
|
33
|
+
# return Tron.success :reset_not_requested unless request.params[:reset]
|
|
34
|
+
|
|
35
|
+
# #storage.reset
|
|
36
|
+
# Tron.success :previous_editing_cleared
|
|
37
|
+
# end
|
|
38
|
+
|
|
39
|
+
def do_ensure_temporary_secret_key
|
|
40
|
+
return Tron.success :secret_key_exists if storage.secret_key
|
|
41
|
+
|
|
42
|
+
storage.generate_secret_key!
|
|
43
|
+
Tron.success :secret_generated
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def do_reveal_otp_secret
|
|
47
|
+
dummy = ::Booth::Models::Credential.new otp_secret_key: storage.secret_key, scope: scope
|
|
48
|
+
|
|
49
|
+
Tron.success :register_otp, step:,
|
|
50
|
+
otp_provisioning_svg: dummy.otp_provisioning_svg,
|
|
51
|
+
otp_provisioning_url: dummy.otp_provisioning_url
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def step
|
|
55
|
+
return :successfully_changed if storage.secret_key_recently_changed?
|
|
56
|
+
|
|
57
|
+
return :confirm if storage.secret_key_has_been_seen?
|
|
58
|
+
|
|
59
|
+
:register
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def storage
|
|
63
|
+
request.storage.otp
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def credential
|
|
67
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
module Guards
|
|
5
|
+
class Manageable
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
include ::Booth::MethodObject
|
|
8
|
+
|
|
9
|
+
option :credential
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return if ::Booth::Credentials::Modes::OtpManageable.call(credential)
|
|
13
|
+
|
|
14
|
+
debug { 'OTP is not relevant to this credential' }
|
|
15
|
+
yield Tron.failure :otp_not_configurable, public_message: I18n.t('booth.otp_unavailable')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
module Guards
|
|
5
|
+
class Sudo
|
|
6
|
+
include ::Booth::MethodObject
|
|
7
|
+
|
|
8
|
+
option :request
|
|
9
|
+
option :credential
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return if credential.mode_first_time?
|
|
13
|
+
return if credential.mode_username_and_password?
|
|
14
|
+
return if credential.mode_username_password_and_webauth?
|
|
15
|
+
return if credential.mode_username_and_webauth?
|
|
16
|
+
|
|
17
|
+
request.sudo.guard_with_otp { yield _1 }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
class Show
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_get!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
request.must_be_logged_in!
|
|
11
|
+
|
|
12
|
+
::Booth::Userland::Otps::Guards::Manageable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Otps::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_show
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_show
|
|
21
|
+
if credential.mode_username_password_and_otp?
|
|
22
|
+
return Tron.success :current_otp, step: :show,
|
|
23
|
+
otp_provisioning_svg: credential.otp_provisioning_svg,
|
|
24
|
+
otp_provisioning_url: credential.otp_provisioning_url
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Tron.success :otp_addable, step: :add
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def credential
|
|
31
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
class Sudo
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_post!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
request.must_be_logged_in!
|
|
11
|
+
|
|
12
|
+
do_find_credential
|
|
13
|
+
.on_success { do_require_credential_has_otp }
|
|
14
|
+
.on_success { do_check_code }
|
|
15
|
+
.on_success { do_grant_sudo }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_find_credential
|
|
21
|
+
@credential = ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
22
|
+
return Tron.success :found_credential if @credential
|
|
23
|
+
|
|
24
|
+
Tron.failure :missing_credential
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def do_require_credential_has_otp
|
|
28
|
+
return Tron.success :credential_has_otp if @credential.mode_username_password_and_otp?
|
|
29
|
+
|
|
30
|
+
Tron.failure :credential_has_no_otp, public_message: I18n.t('booth.otp_unavailable')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def do_check_code
|
|
34
|
+
::Booth::Credentials::OtpAuthentication.call credential: @credential,
|
|
35
|
+
code: code_param,
|
|
36
|
+
ip: request.ip,
|
|
37
|
+
agent: request.agent
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def do_grant_sudo
|
|
41
|
+
request.sudo.otp!
|
|
42
|
+
Tron.success :otp_sudo_granted
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def code_param
|
|
46
|
+
params.require(:otp).permit(:otp)[:otp]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class Confirm
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
def self.applicable?(params:)
|
|
10
|
+
params.key?(:otp) && params[:otp].key?(:otp_confirmation)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_secret_key
|
|
15
|
+
.on_success { do_find_credential }
|
|
16
|
+
.on_success { do_require_eligible_credential }
|
|
17
|
+
.on_success { do_compare_code }
|
|
18
|
+
.on_success { do_update_credential }
|
|
19
|
+
.on_success { do_audit }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def do_check_secret_key
|
|
25
|
+
return Tron.success :secret_key_exists if storage.secret_key.present?
|
|
26
|
+
|
|
27
|
+
Tron.failure :missing_secret_key
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def do_find_credential
|
|
31
|
+
@credential = ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
32
|
+
return Tron.success :found_credential if @credential
|
|
33
|
+
|
|
34
|
+
Tron.failure :missing_credential
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def do_require_eligible_credential
|
|
38
|
+
return Tron.success :can_add_otp if ::Booth::Credentials::Modes::OtpAddable.call(@credential)
|
|
39
|
+
return Tron.success :can_change_otp if ::Booth::Credentials::Modes::OtpChangeable.call(@credential)
|
|
40
|
+
|
|
41
|
+
Tron.failure :credential_not_otpable, public_message: I18n.t('booth.otp_not_eligible')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def do_compare_code
|
|
45
|
+
@credential.otp_secret_key = storage.secret_key
|
|
46
|
+
return Tron.success :correct_code if @credential.authenticate_otp(code_param)
|
|
47
|
+
|
|
48
|
+
debug { "Provided code #{code_param} did not match expected code #{@credential.otp_code}" }
|
|
49
|
+
Tron.failure :wrong_code, public_message: I18n.t('booth.wrong_otp')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def do_update_credential
|
|
53
|
+
@credential.mode = :username_password_and_otp
|
|
54
|
+
|
|
55
|
+
if @credential.save
|
|
56
|
+
request.sudo.otp!
|
|
57
|
+
debug { 'You confirmed your newly changed otp' }
|
|
58
|
+
return Tron.success :otp_confirmed
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
debug { "The confirmation was correct but the update failed: #{@credential.errors.to_a.to_sentence}" }
|
|
62
|
+
Tron.failure :correct_otp_confirmation_failed
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def do_audit
|
|
66
|
+
::Booth::Audits::Register::ChangedOtp.call credential: @credential, ip: request.ip, agent: request.agent
|
|
67
|
+
storage.secret_key_recently_changed!
|
|
68
|
+
|
|
69
|
+
Tron.success :audit_created
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def code_param
|
|
73
|
+
params.require(:otp).permit(:otp_confirmation)[:otp_confirmation]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def storage
|
|
77
|
+
request.storage.otp
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class Register
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
def self.applicable?(params:)
|
|
10
|
+
params&.key?(:register)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_secret_key
|
|
15
|
+
.on_success { do_register_otp }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_check_secret_key
|
|
21
|
+
return Tron.success :secret_key_exists if storage.secret_key.present?
|
|
22
|
+
|
|
23
|
+
Tron.failure :missing_secret_key
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def do_register_otp
|
|
27
|
+
storage.secret_key_has_been_seen!
|
|
28
|
+
|
|
29
|
+
Tron.success :otp_secret_registered
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def storage
|
|
33
|
+
request.storage.otp
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class Reset
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
def self.applicable?(params:)
|
|
10
|
+
params.key?(:reset)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_reset
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def do_reset
|
|
20
|
+
storage.reset
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def storage
|
|
24
|
+
request.storage.otp
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Otps
|
|
4
|
+
class Update
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_patch!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
request.must_be_logged_in!
|
|
11
|
+
|
|
12
|
+
::Booth::Userland::Otps::Guards::Manageable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Otps::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_transition
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def transitions
|
|
21
|
+
[
|
|
22
|
+
::Booth::Userland::Otps::Transitions::Update::Confirm,
|
|
23
|
+
::Booth::Userland::Otps::Transitions::Update::Register,
|
|
24
|
+
::Booth::Userland::Otps::Transitions::Update::Reset,
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def credential
|
|
29
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
class Create
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_post!
|
|
9
|
+
|
|
10
|
+
do_check_logged_out
|
|
11
|
+
.on_success { do_find_credential }
|
|
12
|
+
.on_success { do_remember_email }
|
|
13
|
+
.on_success { do_create_password_reset }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
delegate :username, to: :storage, private: true
|
|
19
|
+
|
|
20
|
+
def do_check_logged_out
|
|
21
|
+
unless request.authentication.logged_in?
|
|
22
|
+
debug { "Good, nobody happens to be already logged in in scope #{request.scope}" }
|
|
23
|
+
return Tron.success :not_logged_in
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
debug do
|
|
27
|
+
"Logged in as user #{request.authentication.username.inspect} but trying to request password reset"
|
|
28
|
+
end
|
|
29
|
+
Tron.failure :logged_in_user_cannot_reset_password, public_message: I18n.t('booth.logged_in_user_cannot_reset_password')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def do_find_credential
|
|
33
|
+
return Tron.success :known_credential if login_storage.credential_for_username
|
|
34
|
+
|
|
35
|
+
Tron.failure :unknown_credential, public_message: I18n.t('booth.password_reset_needs_username')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def do_remember_email
|
|
39
|
+
password_reset_storage.email = ::Booth::Syntaxes::Email.call(email_param).normalized_invalid_email
|
|
40
|
+
|
|
41
|
+
Tron.success :remembered_email
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def do_create_password_reset
|
|
45
|
+
creation = ::Booth::PasswordResets::Create.call(
|
|
46
|
+
credential: login_storage.credential_for_username,
|
|
47
|
+
email: email_param,
|
|
48
|
+
ip: request.ip,
|
|
49
|
+
agent: request.agent
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
creation.on_success do
|
|
53
|
+
password_reset_storage.email = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
creation
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def login_storage
|
|
60
|
+
request.storage.login
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def password_reset_storage
|
|
64
|
+
request.storage.password_reset
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def email_param
|
|
68
|
+
params.require(:password_reset).permit(:email)[:email]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
module Guards
|
|
5
|
+
class LoggedOut
|
|
6
|
+
include ::Booth::MethodObject
|
|
7
|
+
include ::Booth::Logging
|
|
8
|
+
|
|
9
|
+
option :request
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return Tron.success :not_logged_in unless request.authentication.logged_in?
|
|
13
|
+
|
|
14
|
+
debug { "Logged in as user #{request.authentication.username.inspect} but trying to password reset" }
|
|
15
|
+
yield Tron.success :logged_in_user_cannot_reset_password, step: :logout_first
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
class New
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_get!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
|
|
11
|
+
::Booth::Userland::PasswordResets::Guards::LoggedOut.call(request:) { return _1 }
|
|
12
|
+
|
|
13
|
+
do_find_credential
|
|
14
|
+
.on_success { do_prepare_reset_form }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
delegate :username, to: :storage, private: true
|
|
20
|
+
|
|
21
|
+
def do_find_credential
|
|
22
|
+
return Tron.success :known_credential if login_storage.credential_for_username
|
|
23
|
+
|
|
24
|
+
debug { "I don't know the username for a password reset" }
|
|
25
|
+
Tron.failure :unknown_credential, public_message: I18n.t('booth.password_reset_needs_username')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def do_prepare_reset_form
|
|
29
|
+
creation = ::Booth::PasswordResets::Create.call(
|
|
30
|
+
credential: login_storage.credential_for_username,
|
|
31
|
+
email: nil,
|
|
32
|
+
ip: request.ip,
|
|
33
|
+
agent: request.agent
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if creation.failure == :blank_email
|
|
37
|
+
debug { 'Password reset is possible, once email was provided' }
|
|
38
|
+
return Tron.success :email_address_needed, username: login_storage.username,
|
|
39
|
+
email: password_reset_storage.email,
|
|
40
|
+
step: :new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Because we did not pass in an email, this will never be successful.
|
|
44
|
+
creation
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def login_storage
|
|
48
|
+
request.storage.login
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def password_reset_storage
|
|
52
|
+
request.storage.password_reset
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
class Show
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_get!
|
|
9
|
+
request.must_be_html!
|
|
10
|
+
|
|
11
|
+
do_find_password_reset
|
|
12
|
+
.on_success { do_check_scope }
|
|
13
|
+
.on_success { do_check_logged_out }
|
|
14
|
+
.on_success { do_access_password_reset }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def do_find_password_reset
|
|
18
|
+
finding = ::Booth::PasswordResets::Find.call(secret_key: secret_key_param)
|
|
19
|
+
return finding if finding.failure?
|
|
20
|
+
|
|
21
|
+
@password_reset = finding.password_reset
|
|
22
|
+
finding
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def do_check_scope
|
|
26
|
+
::Booth::Syntaxes::ScopeComparison.call this: request.scope, that: @password_reset.credential.scope
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def do_check_logged_out
|
|
30
|
+
unless request.authentication.logged_in?
|
|
31
|
+
debug { "Good, nobody happens to be already logged in in scope #{request.scope}" }
|
|
32
|
+
return Tron.success :not_logged_in
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if request.authentication.logged_in_as?(credential: @password_reset.credential)
|
|
36
|
+
debug { "#{@password_reset.credential.username} is already logged in in scope #{request.scope}" }
|
|
37
|
+
return Tron.success :logged_in_as_same_credential
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# This is not a security issue (the reset link status is checked elsewhere),
|
|
41
|
+
# but we should not ask the user to logout knowing that password reset is unavailble.
|
|
42
|
+
if %i[completed timed_out].include?(@password_reset.step)
|
|
43
|
+
return Tron.failure :wrong_user_and_reset_unavailable, step: @password_reset.step
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
debug do
|
|
47
|
+
"Logged in as user #{request.authentication.username.inspect} but trying to reset password as #{@password_reset.credential.username.inspect}"
|
|
48
|
+
end
|
|
49
|
+
Tron.failure :wrong_user_logged_in, step: :wrong_user_logged_in,
|
|
50
|
+
secret_key: @password_reset.secret_key,
|
|
51
|
+
username: @password_reset.credential.username
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def do_access_password_reset
|
|
55
|
+
# Storing the consumer IP for now, since we already have it.
|
|
56
|
+
if @password_reset.accessed_at.blank?
|
|
57
|
+
@password_reset.update!(accessed_at: Time.current, consumer_ip: request.ip)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
debug do
|
|
61
|
+
"Accessed PasswordReset with ID #{@password_reset.id.inspect} and Credential ID #{@password_reset.credential_id.inspect}"
|
|
62
|
+
end
|
|
63
|
+
Tron.success :password_reset_accessed, credential_id: @password_reset.credential.id,
|
|
64
|
+
step: @password_reset.step,
|
|
65
|
+
username: @password_reset.credential.username,
|
|
66
|
+
secret_key: @password_reset.secret_key,
|
|
67
|
+
minlength: @password_reset.class.password_minlength,
|
|
68
|
+
passwordrules: @password_reset.class.passwordrules
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def secret_key_param
|
|
72
|
+
params[:id]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|