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,48 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class ChoosePassword
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
option :password_reset
|
|
10
|
+
|
|
11
|
+
def self.applicable?(params:)
|
|
12
|
+
params&.key?(:password_reset) && params[:password_reset]&.key?(:password)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
do_check_password_reset
|
|
17
|
+
.on_success { do_update_password }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def do_check_password_reset
|
|
23
|
+
return Tron.failure :missing_password_reset unless password_reset.is_a?(::Booth::Models::PasswordReset)
|
|
24
|
+
|
|
25
|
+
Tron.success :password_reset_exists
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def do_update_password
|
|
29
|
+
if password_reset.update password: password,
|
|
30
|
+
password_chosen_at: Time.current
|
|
31
|
+
debug { 'You chose a password' }
|
|
32
|
+
Tron.success :password_chosen
|
|
33
|
+
else
|
|
34
|
+
public_message = password_reset.errors.to_a.to_sentence
|
|
35
|
+
debug { "Could not choose password: #{public_message}" }
|
|
36
|
+
Tron.failure :password_update_failed, public_message:
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def password
|
|
41
|
+
params&.require(:password_reset)&.permit(:password)&.[](:password)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class ConfirmPassword
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
option :password_reset
|
|
10
|
+
|
|
11
|
+
def self.applicable?(params:)
|
|
12
|
+
params.key?(:password_reset) && params[:password_reset].key?(:password_confirmation)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
do_compare_password
|
|
17
|
+
.on_success { do_update_password }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def do_compare_password
|
|
23
|
+
return Tron.success :passwords_match if @password_reset.authenticate_password(password_param)
|
|
24
|
+
|
|
25
|
+
@password_reset.errors.add :password_confirmation, :confirmation
|
|
26
|
+
public_message = password_reset.errors.to_a.to_sentence
|
|
27
|
+
debug { "Could not confirm password: #{public_message}" }
|
|
28
|
+
Tron.failure :password_did_not_match, public_message:
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def do_update_password
|
|
32
|
+
if @password_reset.update(password_confirmed_at: Time.current, consumer_ip: request.ip)
|
|
33
|
+
debug { 'You confirmed your password' }
|
|
34
|
+
::Booth::PasswordResets::PropagateToCredential.call(@password_reset)
|
|
35
|
+
Tron.success :password_confirmed,
|
|
36
|
+
public_message: I18n.t('booth.password_successfully_reset')
|
|
37
|
+
|
|
38
|
+
else
|
|
39
|
+
debug do
|
|
40
|
+
"The confirmation was correct but the update failed: #{password_reset.errors.to_a.to_sentence}"
|
|
41
|
+
end
|
|
42
|
+
Tron.failure :correct_password_confirmation_failed
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def password_param
|
|
47
|
+
params.require(:password_reset).permit(:password_confirmation)[:password_confirmation]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class ResetPassword
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
option :password_reset
|
|
10
|
+
|
|
11
|
+
def self.applicable?(params:)
|
|
12
|
+
params.key?(:reset_password)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
if password_reset.update password_chosen_at: nil, password_confirmed_at: nil
|
|
17
|
+
debug { 'The PasswordReset password was reset.' }
|
|
18
|
+
Tron.success :password_reset
|
|
19
|
+
else
|
|
20
|
+
debug { "Could not reset password: #{password_reset.errors.to_a.to_sentence}" }
|
|
21
|
+
Tron.failure :password_reset_failed
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module PasswordResets
|
|
4
|
+
class Update
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_patch!
|
|
9
|
+
|
|
10
|
+
do_find_password_reset
|
|
11
|
+
.on_success { do_check_scope }
|
|
12
|
+
.on_success { do_check_logged_out }
|
|
13
|
+
.on_success { do_transition }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def do_find_password_reset
|
|
19
|
+
finding = ::Booth::PasswordResets::Find.call(secret_key: params[:id])
|
|
20
|
+
return finding if finding.failure?
|
|
21
|
+
|
|
22
|
+
@password_reset = finding.password_reset
|
|
23
|
+
finding
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def do_check_scope
|
|
27
|
+
::Booth::Syntaxes::ScopeComparison.call this: scope, that: @password_reset.credential.scope
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def do_check_logged_out
|
|
31
|
+
unless request.authentication.logged_in?
|
|
32
|
+
debug { "Good, nobody happens to be already logged in in scope #{scope}" }
|
|
33
|
+
return Tron.success :not_logged_in
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
debug { "When updating a new password, nobody should be logged in its scope #{scope.inspect}" }
|
|
37
|
+
Tron.failure :currently_logged_in
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def after_transition
|
|
41
|
+
@password_reset.reload # Ensure the `password_reset` instance is in a valid state after a failed update
|
|
42
|
+
debug { "PasswordReset updated, now in status #{@password_reset.step}" }
|
|
43
|
+
|
|
44
|
+
# If (and only if!) this account is protected *only* by a password...
|
|
45
|
+
return unless @password_reset.completed? && @password_reset.credential.mode_username_and_password?
|
|
46
|
+
|
|
47
|
+
# ...then we log in right away.
|
|
48
|
+
::Booth::Sessions::CreateAndLogin.call(credential: @password_reset.credential, request:)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def initialize_transition
|
|
52
|
+
transition.call(password_reset: @password_reset, request:)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def transitions
|
|
56
|
+
[
|
|
57
|
+
::Booth::Userland::PasswordResets::Transitions::Update::ChoosePassword,
|
|
58
|
+
::Booth::Userland::PasswordResets::Transitions::Update::ConfirmPassword,
|
|
59
|
+
::Booth::Userland::PasswordResets::Transitions::Update::ResetPassword,
|
|
60
|
+
]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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
|
+
|
|
12
|
+
::Booth::Userland::Passwords::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
13
|
+
|
|
14
|
+
do_require_eligible_credential
|
|
15
|
+
.on_success { do_destroy }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_require_eligible_credential
|
|
21
|
+
return Tron.success :can_remove_password if ::Booth::Credentials::Modes::PasswordRemovable.call(credential)
|
|
22
|
+
|
|
23
|
+
Tron.failure :credential_not_passwordable, public_message: I18n.t('booth.password_not_eligible')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def do_destroy
|
|
27
|
+
if credential.mode_username_and_webauth!
|
|
28
|
+
debug { 'Password has been removed from this credential' }
|
|
29
|
+
return Tron.success :password_removed, public_message: I18n.t('booth.password_removed')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Tron.failure :password_removal_failed
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def credential
|
|
36
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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::Passwords::Guards::Manageable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Passwords::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_clear_timed_out_sudo
|
|
16
|
+
.on_success { do_edit_password }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
delegate :sudo, :authentication, to: :request
|
|
22
|
+
|
|
23
|
+
def do_clear_timed_out_sudo
|
|
24
|
+
return Tron.success :sudo_still_granted if sudo.password?
|
|
25
|
+
|
|
26
|
+
# If you had chosen a new password and your sudo ran out,
|
|
27
|
+
# then we should also clear the chosen password again. Simply start all over.
|
|
28
|
+
storage.password_digest = nil
|
|
29
|
+
Tron.success :cleared_password_digest
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def do_edit_password
|
|
33
|
+
Tron.success :editing_password, step:
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def step
|
|
37
|
+
return :successfully_changed if storage.password_recently_changed?
|
|
38
|
+
return :enter_old_password unless sudo.password?
|
|
39
|
+
return :choose_new_password if storage.password_digest.blank?
|
|
40
|
+
|
|
41
|
+
:confirm_new_password
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def storage
|
|
45
|
+
request.storage.password
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def credential
|
|
49
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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::PasswordManageable.call(credential)
|
|
13
|
+
|
|
14
|
+
debug { 'Password is not relevant to this credential' }
|
|
15
|
+
yield Tron.failure :password_not_configurable, public_message: I18n.t('booth.password_unavailable')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
module Guards
|
|
5
|
+
class Removable
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
include ::Booth::MethodObject
|
|
8
|
+
|
|
9
|
+
option :credential
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return if ::Booth::Credentials::Modes::PasswordRemovable.call(credential)
|
|
13
|
+
|
|
14
|
+
debug { 'Password is not removable from this credential' }
|
|
15
|
+
yield Tron.failure :password_not_removable, public_message: I18n.t('booth.password_unavailable')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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_webauth?
|
|
14
|
+
|
|
15
|
+
request.sudo.guard_with_password { yield _1 }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
class Remove
|
|
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::Passwords::Guards::Removable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Passwords::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_render
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_render
|
|
21
|
+
Tron.success :todo, step:
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def step
|
|
25
|
+
::Booth::Userland::Passwords::Transitions::Remove::Step.call(credential:)
|
|
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,32 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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::Passwords::Guards::Manageable.call(credential:) { return _1 }
|
|
13
|
+
::Booth::Userland::Passwords::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
14
|
+
|
|
15
|
+
do_show
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def do_show
|
|
21
|
+
return Tron.success(:otp_addable, step: :add) if credential.mode_username_and_webauth?
|
|
22
|
+
|
|
23
|
+
Tron.success :manage_password, step: :show
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def credential
|
|
27
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
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_password }
|
|
14
|
+
.on_success { do_check_password }
|
|
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_password
|
|
28
|
+
return Tron.success :credential_has_only_password if @credential.mode_username_and_password?
|
|
29
|
+
return Tron.success :credential_has_password_and_otp if @credential.mode_username_password_and_otp?
|
|
30
|
+
return Tron.success :credential_has_password_and_webauth if @credential.mode_username_password_and_webauth?
|
|
31
|
+
|
|
32
|
+
Tron.failure :credential_has_no_password, public_message: I18n.t('booth.password_not_configured')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def do_check_password
|
|
36
|
+
::Booth::Credentials::PasswordAuthentication.call(
|
|
37
|
+
credential: @credential,
|
|
38
|
+
password: password_param,
|
|
39
|
+
ip: request.ip,
|
|
40
|
+
agent: request.agent
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def do_grant_sudo
|
|
45
|
+
request.sudo.password!
|
|
46
|
+
Tron.success :password_sudo_granted
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def password_param
|
|
50
|
+
params.require(:password).permit(:password)[:password]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
module Transitions
|
|
5
|
+
module Remove
|
|
6
|
+
class Step
|
|
7
|
+
include ::Booth::MethodObject
|
|
8
|
+
|
|
9
|
+
option :credential
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return :add_authenticator if authenticators.none?(&:supports_user_verification)
|
|
13
|
+
|
|
14
|
+
:remove
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def authenticators
|
|
20
|
+
credential.authenticators.registered_scope
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class ChoosePassword
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
def self.applicable?(params:)
|
|
10
|
+
params.dig(:password, :new_password)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_sudo
|
|
15
|
+
.on_success { do_check_password }
|
|
16
|
+
.on_success { do_remember_password }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def do_check_sudo
|
|
22
|
+
return Tron.success :still_has_sudo if sudo.password?
|
|
23
|
+
|
|
24
|
+
Tron.failure :missing_sudo, public_message: I18n.t('booth.password_change_timeout',
|
|
25
|
+
lifespan_minutes: (sudo.lifespan / 60))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def do_check_password
|
|
29
|
+
@dummy_credential = ::Booth::Models::Credential.new(
|
|
30
|
+
password: password_param,
|
|
31
|
+
username: :dummy,
|
|
32
|
+
allowed_modes: [:first_time]
|
|
33
|
+
)
|
|
34
|
+
return Tron.success :password_is_acceptable if @dummy_credential.valid?
|
|
35
|
+
|
|
36
|
+
debug { 'The newly chosen password is not acceptable' }
|
|
37
|
+
Tron.failure :invalid_password, public_message: @dummy_credential.errors.full_messages.to_sentence
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def do_remember_password
|
|
41
|
+
storage.password_digest = @dummy_credential.password_digest
|
|
42
|
+
|
|
43
|
+
Tron.success :remembered_password
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def password_param
|
|
47
|
+
params.require(:password).permit(:new_password)[:new_password]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def storage
|
|
51
|
+
request.storage.password
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sudo
|
|
55
|
+
request.sudo
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
module Transitions
|
|
5
|
+
module Update
|
|
6
|
+
class ConfirmPassword
|
|
7
|
+
include ::Booth::Concerns::Transition
|
|
8
|
+
|
|
9
|
+
def self.applicable?(params:)
|
|
10
|
+
params.dig(:password, :password)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_sudo
|
|
15
|
+
.on_success { do_compare_password }
|
|
16
|
+
.on_success { do_update_credential }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def do_check_sudo
|
|
22
|
+
return Tron.success :still_has_sudo if sudo.password?
|
|
23
|
+
|
|
24
|
+
Tron.failure :missing_sudo, public_message: I18n.t('booth.password_change_timeout',
|
|
25
|
+
lifespan_minutes: (sudo.lifespan / 60))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def do_compare_password
|
|
29
|
+
@dummy_credential = ::Booth::Models::Credential.new(
|
|
30
|
+
password_digest: storage.password_digest,
|
|
31
|
+
password_confirmation: password_param,
|
|
32
|
+
username: :dummy,
|
|
33
|
+
allowed_modes: [:first_time]
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if @dummy_credential.valid?
|
|
37
|
+
debug { 'The password confirmation was typed in correctly' }
|
|
38
|
+
return Tron.success :passwords_match
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
debug { 'The password confirmation did not match' }
|
|
42
|
+
Tron.failure :passwords_dont_match, public_message: @dummy_credential.errors.full_messages.to_sentence
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def do_update_credential
|
|
46
|
+
credential = ::Booth::Models::Credential.find(authentication.credential_id)
|
|
47
|
+
|
|
48
|
+
if credential.update(password: password_param)
|
|
49
|
+
debug { "Successfully updated password of credential with ID #{credential.id}" }
|
|
50
|
+
storage.reset
|
|
51
|
+
storage.password_recently_changed!
|
|
52
|
+
|
|
53
|
+
# Prolong sudo to give the user more time to revoke all other sessions.
|
|
54
|
+
sudo.password!
|
|
55
|
+
return Tron.success :password_updated
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
debug { "Could not persist new password for credential with ID #{credential.id}" }
|
|
59
|
+
Tron.failure :persistence_failed, public_message: credential.errors.full_messages.to_sentence
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def password_param
|
|
63
|
+
params.require(:password).permit(:password)[:password]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def storage
|
|
67
|
+
request.storage.password
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def authentication
|
|
71
|
+
request.authentication
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def sudo
|
|
75
|
+
request.sudo
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Userland
|
|
3
|
+
module Passwords
|
|
4
|
+
class Update
|
|
5
|
+
include ::Booth::Concerns::Action
|
|
6
|
+
|
|
7
|
+
def call
|
|
8
|
+
request.must_be_patch!
|
|
9
|
+
request.must_be_logged_in!
|
|
10
|
+
|
|
11
|
+
::Booth::Userland::Passwords::Guards::Manageable.call(credential:) { return _1 }
|
|
12
|
+
::Booth::Userland::Passwords::Guards::Sudo.call(request:, credential:) { return _1 }
|
|
13
|
+
|
|
14
|
+
do_transition
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def credential
|
|
20
|
+
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def transitions
|
|
24
|
+
[
|
|
25
|
+
::Booth::Userland::Passwords::Transitions::Update::ChoosePassword,
|
|
26
|
+
# TODO: Add ResetPassword so that you can change your mind when confirming
|
|
27
|
+
::Booth::Userland::Passwords::Transitions::Update::ConfirmPassword,
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|