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,63 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
module Onboardings
|
|
4
|
+
class Create
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
|
|
8
|
+
option :credential_id
|
|
9
|
+
|
|
10
|
+
def call
|
|
11
|
+
find_action.on_success { validate_action }
|
|
12
|
+
.on_success { save_action }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def find_action
|
|
18
|
+
if credential
|
|
19
|
+
debug { "Found the credential with id #{credential_id.inspect}, deleting any current onboardings" }
|
|
20
|
+
::Booth::Models::Onboarding.where(credential_id: credential.id).destroy_all
|
|
21
|
+
Tron.success :credential_exists
|
|
22
|
+
else
|
|
23
|
+
warn { "Could not find credential with id #{credential_id.inspect}" }
|
|
24
|
+
Tron.failure :credential_not_found
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def validate_action
|
|
29
|
+
if onboarding.valid?
|
|
30
|
+
debug { 'The new onboarding record is valid' }
|
|
31
|
+
Tron.success :record_is_valid
|
|
32
|
+
else
|
|
33
|
+
debug { "The new onboarding record is invalid: #{onboarding.errors.full_messages.to_sentence}" }
|
|
34
|
+
Tron.failure :invalid_record, message: onboarding.errors.full_messages.to_sentence
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def save_action
|
|
39
|
+
if onboarding.save
|
|
40
|
+
debug { 'Successfully persisted a new onboarding record' }
|
|
41
|
+
Tron.success :onboarding_created, id: onboarding.id, credential_id: credential.id,
|
|
42
|
+
secret_key: onboarding.secret_key
|
|
43
|
+
else
|
|
44
|
+
debug { 'Could not persist a new onboarding record' }
|
|
45
|
+
Tron.failure :persistence_failed, message: onboarding.errors.full_messages.to_sentence
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def credential
|
|
50
|
+
return @credential if defined?(@credential)
|
|
51
|
+
|
|
52
|
+
@credential = ::Booth::Models::Credential.find_by(id: credential_id)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def onboarding
|
|
56
|
+
@onboarding ||= ::Booth::Models::Onboarding.new(
|
|
57
|
+
credential_id:
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
module Onboardings
|
|
4
|
+
class Destroy
|
|
5
|
+
include ::Booth::Logging
|
|
6
|
+
include ::Booth::MethodObject
|
|
7
|
+
|
|
8
|
+
option :id, as: :raw_id
|
|
9
|
+
|
|
10
|
+
def call
|
|
11
|
+
do_verify_id
|
|
12
|
+
.on_success { do_find_record }
|
|
13
|
+
.on_success { do_destroy_record }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def do_verify_id
|
|
17
|
+
return Tron.success :valid_id_syntax if id
|
|
18
|
+
|
|
19
|
+
debug { "Invalid Onboarding ID #{raw_id.inspect}" }
|
|
20
|
+
Tron.failure :invalid_id_syntax, id:, credential_id: nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def do_find_record
|
|
24
|
+
return Tron.success :record_found if record
|
|
25
|
+
|
|
26
|
+
debug { "Could not find Onboarding with ID #{id.inspect}" }
|
|
27
|
+
Tron.failure :onboarding_not_found, id: nil, credential_id: nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def do_destroy_record
|
|
31
|
+
return Tron.success(:onboarding_deleted, id: record.id, credential_id:) if record.destroy
|
|
32
|
+
|
|
33
|
+
Tron.failure :could_not_delete_onboarding, id: record.id, credential_id:
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
delegate :credential_id, to: :record, allow_nil: true
|
|
39
|
+
|
|
40
|
+
def id
|
|
41
|
+
::Booth::Syntaxes::Uuid.call(raw_id, raise_if_invalid: false).uuid
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def record
|
|
45
|
+
@record ||= ::Booth::Models::Onboarding.find_by(id:)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
module Onboardings
|
|
4
|
+
class Find
|
|
5
|
+
include ::Booth::Logging
|
|
6
|
+
include ::Booth::MethodObject
|
|
7
|
+
|
|
8
|
+
option :id, default: -> {}
|
|
9
|
+
option :credential_id, default: -> {}, as: :raw_credential_id
|
|
10
|
+
option :raise_if_missing, default: -> { false }
|
|
11
|
+
option :only_unused, default: -> { false }
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_id
|
|
15
|
+
.on_success { do_find_onboarding }
|
|
16
|
+
.on_success { do_check_used }
|
|
17
|
+
.on_success { do_serialize_onboarding }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def do_check_id
|
|
23
|
+
return Tron.success(:id_is_valid) if onboarding_id || credential_id
|
|
24
|
+
|
|
25
|
+
Tron.failure :no_id_provided, record: nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def do_find_onboarding
|
|
29
|
+
@onboarding = if onboarding_id
|
|
30
|
+
::Booth::Models::Onboarding.find_by(id: onboarding_id)
|
|
31
|
+
else
|
|
32
|
+
::Booth::Models::Onboarding.find_by(credential_id:)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
return Tron.success :onboarding_exists if @onboarding
|
|
36
|
+
|
|
37
|
+
if onboarding_id
|
|
38
|
+
debug { "Couldn't find Onboarding with ID #{onboarding_id.inspect}" }
|
|
39
|
+
else
|
|
40
|
+
debug { "Couldn't find Onboarding with credential ID #{credential_id.inspect}" }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result = Tron.failure :onboarding_not_found, provided_onboarding_id: id.inspect,
|
|
44
|
+
provided_credential_id: raw_credential_id.inspect,
|
|
45
|
+
record: nil
|
|
46
|
+
raise result if raise_if_missing
|
|
47
|
+
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def do_check_used
|
|
52
|
+
return Tron.success :onboarding_is_new if @onboarding.step == :choose_mode
|
|
53
|
+
return Tron.success :we_allow_used_onboardings unless only_unused
|
|
54
|
+
|
|
55
|
+
error = Tron.failure(:onboarding_already_used, provided_onboarding_id: id.inspect,
|
|
56
|
+
provided_credential_id: raw_credential_id.inspect,
|
|
57
|
+
record: nil)
|
|
58
|
+
raise error if raise_if_missing
|
|
59
|
+
|
|
60
|
+
error
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def do_serialize_onboarding
|
|
64
|
+
attributes = @onboarding.attributes
|
|
65
|
+
.symbolize_keys
|
|
66
|
+
.slice(:id, :credential_id, :secret_key, :accessed_at, :mode)
|
|
67
|
+
.merge(additional_attributes)
|
|
68
|
+
|
|
69
|
+
debug { "Onboarding found ID #{@onboarding.id.inspect} and Credential ID #{@onboarding.credential_id.inspect}" }
|
|
70
|
+
Tron.success(:onboarding_found, record: ::Booth::ToStruct.call(attributes))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Helpers
|
|
74
|
+
|
|
75
|
+
def onboarding_id
|
|
76
|
+
::Booth::Syntaxes::Uuid.call(id, raise_if_invalid: false).uuid
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def credential_id
|
|
80
|
+
::Booth::Syntaxes::Uuid.call(raw_credential_id, raise_if_invalid: false).uuid
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def additional_attributes
|
|
84
|
+
{
|
|
85
|
+
step: @onboarding.step,
|
|
86
|
+
username: @onboarding.username,
|
|
87
|
+
is_completed: @onboarding.completed?,
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
module Onboardings
|
|
4
|
+
class Index
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :scope, ->(scope) { ::Booth::Syntaxes::Scope.call(scope).normalized_scope }
|
|
8
|
+
|
|
9
|
+
def call
|
|
10
|
+
Tron.success(:all_onboardings, records:)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def records
|
|
16
|
+
::Booth::Models::Onboarding.includes_scope
|
|
17
|
+
.sorted_scope
|
|
18
|
+
.where(credential: { scope: })
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
module Recoveries
|
|
4
|
+
# When sending out username recovery emails,
|
|
5
|
+
# this class helps to keep the sending mechanism idempodent.
|
|
6
|
+
class Consume
|
|
7
|
+
include ::Booth::MethodObject
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :recovery_id
|
|
11
|
+
option :credential_id
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_find_recovery
|
|
15
|
+
.on_success { do_find_credential }
|
|
16
|
+
.on_success { do_check_eligibility }
|
|
17
|
+
.on_success { do_consume }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def do_find_recovery
|
|
23
|
+
debug { "Looking for Recovery with ID #{recovery_id.inspect}" }
|
|
24
|
+
@recovery = ::Booth::Models::Recovery.find_by(id: recovery_id)
|
|
25
|
+
|
|
26
|
+
if @recovery
|
|
27
|
+
debug { 'Recovery was found' }
|
|
28
|
+
return Tron.success :recovery_exists
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
debug { 'Did not find Recovery' }
|
|
32
|
+
Tron.failure :recovery_not_found, provided_id: recovery_id.inspect
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def do_find_credential
|
|
36
|
+
debug { "Looking for Credential with ID #{credential_id.inspect}" }
|
|
37
|
+
@credential = ::Booth::Models::Credential.find_by(id: credential_id)
|
|
38
|
+
|
|
39
|
+
if @credential
|
|
40
|
+
debug { 'Credential was found' }
|
|
41
|
+
return Tron.success :credential_exists
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
debug { 'Did not find Credential' }
|
|
45
|
+
Tron.failure :credential_not_found, provided_id: credential_id.inspect
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def do_check_eligibility
|
|
49
|
+
return Tron.failure :already_consumed if @recovery.consumed?
|
|
50
|
+
|
|
51
|
+
return Tron.failure :already_revoked if @recovery.revoked?
|
|
52
|
+
|
|
53
|
+
Tron.success :can_be_consumed
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def do_consume
|
|
57
|
+
@recovery.transaction do
|
|
58
|
+
@recovery.update! consumed_at: Time.current
|
|
59
|
+
|
|
60
|
+
@recovery.other_recoveries_with_this_scope_and_email
|
|
61
|
+
.update_all revoked_at: Time.current # rubocop:disable Rails/SkipsModelValidations
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Tron.success :recovery_consumed, email: @recovery.email,
|
|
65
|
+
username: @credential.username
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Adminland
|
|
3
|
+
# ------------------
|
|
4
|
+
# Credential Helpers
|
|
5
|
+
# ------------------
|
|
6
|
+
|
|
7
|
+
def self.create_credential(...)
|
|
8
|
+
::Booth::Adminland::Credentials::Create.call(...)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ------------------
|
|
13
|
+
# Onboarding Helpers
|
|
14
|
+
# ------------------
|
|
15
|
+
|
|
16
|
+
def self.create_onboarding(...)
|
|
17
|
+
::Booth::Adminland::Onboardings::Create.call(...)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.destroy_onboarding(...)
|
|
21
|
+
::Booth::Adminland::Onboardings::Destroy.call(...)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.find_onboarding(...)
|
|
25
|
+
::Booth::Adminland::Onboardings::Find.call(...)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.find_onboarding_for_mail_delivery(id:)
|
|
29
|
+
::Booth::Adminland::Onboardings::Find.call(id:, only_unused: true, raise_if_missing: true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.index_onboardings(...)
|
|
33
|
+
::Booth::Adminland::Onboardings::Index.call(...)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Other
|
|
39
|
+
|
|
40
|
+
def self.consume_recovery(...)
|
|
41
|
+
::Booth::Adminland::Recoveries::Consume.call(...)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.periodic_cleanup(...)
|
|
45
|
+
::Booth::Adminland::PeriodicCleanup.call(...)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class AddedOtp
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :added_otp
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class ChangedOtp
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :changed_otp
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class CompletedOnboarding
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :completed_onboarding
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class CorrectOtp
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
|
|
8
|
+
option :credential
|
|
9
|
+
option :ip
|
|
10
|
+
option :agent
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
::Booth::Models::Audit.transaction do
|
|
14
|
+
register_attempt!
|
|
15
|
+
clear_failed_attempts!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def register_attempt!
|
|
24
|
+
debug { "Auditing correct OTP for credential `#{credential.id}` and IP `#{ip}`" }
|
|
25
|
+
|
|
26
|
+
::Booth::Models::Audit.create! credential:,
|
|
27
|
+
ip:,
|
|
28
|
+
agent:,
|
|
29
|
+
event: :entered_correct_password
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def clear_failed_attempts!
|
|
33
|
+
debug { "Redeeming all failed OTP attempts for credential `#{credential.id}`" }
|
|
34
|
+
|
|
35
|
+
::Booth::Models::Audit.where(credential:)
|
|
36
|
+
.where(event: :entered_wrong_otp)
|
|
37
|
+
.update_all(deleted_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class CorrectPassword
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
|
|
8
|
+
option :credential
|
|
9
|
+
option :ip
|
|
10
|
+
option :agent
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
::Booth::Models::Audit.transaction do
|
|
14
|
+
register_attempt!
|
|
15
|
+
clear_failed_attempts!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def register_attempt!
|
|
24
|
+
debug { "Auditing correct password for credential `#{credential.id}` and IP `#{ip}`" }
|
|
25
|
+
|
|
26
|
+
::Booth::Models::Audit.create! credential:,
|
|
27
|
+
ip:,
|
|
28
|
+
agent:,
|
|
29
|
+
event: :entered_correct_password
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def clear_failed_attempts!
|
|
33
|
+
debug { "Redeeming failed password attempts for credential `#{credential.id}` and IP `#{ip}`" }
|
|
34
|
+
|
|
35
|
+
::Booth::Models::Audit.where(credential:)
|
|
36
|
+
.where(ip:)
|
|
37
|
+
.where(event: :entered_wrong_password)
|
|
38
|
+
.update_all(deleted_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class Logout
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :logout
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class RequestedPasswordReset
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :requested_password_reset
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class WrongOtp
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
|
|
7
|
+
option :credential
|
|
8
|
+
option :ip
|
|
9
|
+
option :agent
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
13
|
+
ip: ip,
|
|
14
|
+
agent: agent,
|
|
15
|
+
event: :entered_wrong_otp
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Audits
|
|
3
|
+
module Register
|
|
4
|
+
class WrongPassword
|
|
5
|
+
include ::Booth::MethodObject
|
|
6
|
+
include ::Booth::Logging
|
|
7
|
+
|
|
8
|
+
option :credential
|
|
9
|
+
option :ip
|
|
10
|
+
option :agent
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
debug { 'Auditing wrong password...' }
|
|
14
|
+
|
|
15
|
+
::Booth::Models::Audit.create! credential: credential,
|
|
16
|
+
ip: ip,
|
|
17
|
+
agent: agent,
|
|
18
|
+
event: :entered_wrong_password
|
|
19
|
+
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Authenticators
|
|
3
|
+
class Confirm
|
|
4
|
+
include ::Booth::MethodObject
|
|
5
|
+
include ::Booth::Logging
|
|
6
|
+
|
|
7
|
+
option :authenticator
|
|
8
|
+
option :sign_count
|
|
9
|
+
|
|
10
|
+
def call
|
|
11
|
+
raise 'Authenticator is already confirmed' if authenticator.confirmed_at
|
|
12
|
+
|
|
13
|
+
debug { 'Confirming Authenticator...' }
|
|
14
|
+
authenticator.transaction do
|
|
15
|
+
authenticator.update! sign_count: sign_count,
|
|
16
|
+
confirmed_at: Time.current
|
|
17
|
+
|
|
18
|
+
authenticator.credential.update! mode: new_mode
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Tron.success :confirmation_successful
|
|
22
|
+
rescue ActiveRecord::ActiveRecordError => e
|
|
23
|
+
error { e }
|
|
24
|
+
Tron.failure :confirmation_failed
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def new_mode
|
|
30
|
+
::Booth::Authenticators::CredentialModeAfterConfirmation.call(authenticator:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Booth
|
|
2
|
+
module Authenticators
|
|
3
|
+
class CredentialModeAfterConfirmation
|
|
4
|
+
include ::Booth::MethodObject
|
|
5
|
+
|
|
6
|
+
option :authenticator
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
return :username_and_webauth if credential.mode_username_and_webauth?
|
|
10
|
+
return :username_password_and_webauth if credential.mode_username_password_and_webauth?
|
|
11
|
+
|
|
12
|
+
return :username_and_webauth if credential.mode_first_time? &&
|
|
13
|
+
authenticator.supports_user_verification?
|
|
14
|
+
|
|
15
|
+
return :username_password_and_webauth if credential.mode_username_and_password? ||
|
|
16
|
+
credential.mode_username_password_and_otp?
|
|
17
|
+
|
|
18
|
+
raise "Cannot add webauth for credential #{credential.id} with mode #{credential.mode} " \
|
|
19
|
+
"and authenticator #{authenticator.id} (user verification: #{authenticator.supports_user_verification?})"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
delegate :credential, to: :authenticator
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|