summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2019-07-22 10:48:50 +0200
committerGitHub <noreply@github.com>2019-07-22 10:48:50 +0200
commit964ae8eee593687f922c873fa7b378bb6e3e39bb (patch)
treeeb67d6521d6cecc6679e75800c4d170ea5883fa0
parentfea903f574cd59e6938c775427727337d7f929c3 (diff)
Change unconfirmed user login behaviour (#11375)
Allow access to account settings, 2FA, authorized applications, and account deletions to unconfirmed and pending users, as well as users who had their accounts disabled. Suspended users cannot update their e-mail or password or delete their account. Display account status on account settings page, for example, when an account is frozen, limited, unconfirmed or pending review. After sign up, login users straight away and show a simple page that tells them the status of their account with links to account settings and logout, to reduce onboarding friction and allow users to correct wrongly typed e-mail addresses. Move the final sign-up step of SSO integrations to be the same as above to reduce code duplication.
-rw-r--r--app/controllers/about_controller.rb2
-rw-r--r--app/controllers/api/base_controller.rb2
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/controllers/auth/confirmations_controller.rb21
-rw-r--r--app/controllers/auth/omniauth_callbacks_controller.rb2
-rw-r--r--app/controllers/auth/registrations_controller.rb9
-rw-r--r--app/controllers/auth/sessions_controller.rb4
-rw-r--r--app/controllers/auth/setup_controller.rb58
-rw-r--r--app/controllers/oauth/authorized_applications_controller.rb2
-rw-r--r--app/controllers/settings/deletes_controller.rb7
-rw-r--r--app/controllers/settings/sessions_controller.rb2
-rw-r--r--app/controllers/settings/two_factor_authentication/confirmations_controller.rb2
-rw-r--r--app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb2
-rw-r--r--app/controllers/settings/two_factor_authentications_controller.rb2
-rw-r--r--app/javascript/styles/mastodon/admin.scss58
-rw-r--r--app/javascript/styles/mastodon/forms.scss7
-rw-r--r--app/models/concerns/omniauthable.rb2
-rw-r--r--app/models/user.rb6
-rw-r--r--app/views/auth/confirmations/finish_signup.html.haml15
-rw-r--r--app/views/auth/registrations/_sessions.html.haml4
-rw-r--r--app/views/auth/registrations/_status.html.haml16
-rw-r--r--app/views/auth/registrations/edit.html.haml35
-rw-r--r--app/views/auth/setup/show.html.haml23
-rw-r--r--app/views/oauth/authorized_applications/index.html.haml2
-rw-r--r--config/locales/en.yml9
-rw-r--r--config/routes.rb5
-rw-r--r--db/seeds.rb2
-rw-r--r--spec/controllers/api/base_controller_spec.rb42
-rw-r--r--spec/controllers/application_controller_spec.rb4
-rw-r--r--spec/controllers/auth/confirmations_controller_spec.rb41
-rw-r--r--spec/controllers/auth/registrations_controller_spec.rb25
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb4
-rw-r--r--spec/controllers/settings/deletes_controller_spec.rb17
-rw-r--r--spec/features/log_in_spec.rb4
-rw-r--r--spec/models/user_spec.rb4
35 files changed, 298 insertions, 148 deletions
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index 33bac9bbc72..31cf177105b 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -7,7 +7,7 @@ class AboutController < ApplicationController
before_action :set_instance_presenter
before_action :set_expires_in
- skip_before_action :check_user_permissions, only: [:more, :terms]
+ skip_before_action :require_functional!, only: [:more, :terms]
def show; end
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index eca558f4216..6f33a1ea994 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -7,7 +7,7 @@ class Api::BaseController < ApplicationController
include RateLimitHeaders
skip_before_action :store_current_location
- skip_before_action :check_user_permissions
+ skip_before_action :require_functional!
before_action :set_cache_headers
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b8a1faf77e7..41ce1a0ca22 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -25,7 +25,7 @@ class ApplicationController < ActionController::Base
rescue_from Mastodon::NotPermittedError, with: :forbidden
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
- before_action :check_user_permissions, if: :user_signed_in?
+ before_action :require_functional!, if: :user_signed_in?
def raise_not_found
raise ActionController::RoutingError, "No route matches #{params[:unmatched_route]}"
@@ -57,8 +57,8 @@ class ApplicationController < ActionController::Base
forbidden unless current_user&.staff?
end
- def check_user_permissions
- forbidden if current_user.disabled? || current_user.account.suspended?
+ def require_functional!
+ redirect_to edit_user_registration_path unless current_user.functional?
end
def after_sign_out_path_for(_resource_or_scope)
diff --git a/app/controllers/auth/confirmations_controller.rb b/app/controllers/auth/confirmations_controller.rb
index c28c7471c0d..0d7c6e7c2d3 100644
--- a/app/controllers/auth/confirmations_controller.rb
+++ b/app/controllers/auth/confirmations_controller.rb
@@ -4,34 +4,15 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth'
before_action :set_body_classes
- before_action :set_user, only: [:finish_signup]
- def finish_signup
- return unless request.patch? && params[:user]
-
- if @user.update(user_params)
- @user.skip_reconfirmation!
- bypass_sign_in(@user)
- redirect_to root_path, notice: I18n.t('devise.confirmations.send_instructions')
- else
- @show_errors = true
- end
- end
+ skip_before_action :require_functional!
private
- def set_user
- @user = current_user
- end
-
def set_body_classes
@body_classes = 'lighter'
end
- def user_params
- params.require(:user).permit(:email)
- end
-
def after_confirmation_path_for(_resource_name, user)
if user.created_by_application && truthy_param?(:redirect_to_app)
user.created_by_application.redirect_uri
diff --git a/app/controllers/auth/omniauth_callbacks_controller.rb b/app/controllers/auth/omniauth_callbacks_controller.rb
index bbf63bed304..682c77016fd 100644
--- a/app/controllers/auth/omniauth_callbacks_controller.rb
+++ b/app/controllers/auth/omniauth_callbacks_controller.rb
@@ -27,7 +27,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
if resource.email_verified?
root_path
else
- finish_signup_path
+ auth_setup_path(missing_email: '1')
end
end
end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 83797cf1f76..019caf9c1aa 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -9,6 +9,9 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :set_sessions, only: [:edit, :update]
before_action :set_instance_presenter, only: [:new, :create, :update]
before_action :set_body_classes, only: [:new, :create, :edit, :update]
+ before_action :require_not_suspended!, only: [:update]
+
+ skip_before_action :require_functional!, only: [:edit, :update]
def new
super(&:build_invite_request)
@@ -43,7 +46,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
end
def after_sign_up_path_for(_resource)
- new_user_session_path
+ auth_setup_path
end
def after_sign_in_path_for(_resource)
@@ -102,4 +105,8 @@ class Auth::RegistrationsController < Devise::RegistrationsController
def set_sessions
@sessions = current_user.session_activations
end
+
+ def require_not_suspended!
+ forbidden if current_account.suspended?
+ end
end
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index fb8615c3134..7e6dbf19e84 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -6,8 +6,10 @@ class Auth::SessionsController < Devise::SessionsController
layout 'auth'
skip_before_action :require_no_authentication, only: [:create]
- skip_before_action :check_user_permissions, only: [:destroy]
+ skip_before_action :require_functional!
+
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
+
before_action :set_instance_presenter, only: [:new]
before_action :set_body_classes
diff --git a/app/controllers/auth/setup_controller.rb b/app/controllers/auth/setup_controller.rb
new file mode 100644
index 00000000000..46c5f295817
--- /dev/null
+++ b/app/controllers/auth/setup_controller.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+class Auth::SetupController < ApplicationController
+ layout 'auth'
+
+ before_action :authenticate_user!
+ before_action :require_unconfirmed_or_pending!
+ before_action :set_body_classes
+ before_action :set_user
+
+ skip_before_action :require_functional!
+
+ def show
+ flash.now[:notice] = begin
+ if @user.pending?
+ I18n.t('devise.registrations.signed_up_but_pending')
+ else
+ I18n.t('devise.registrations.signed_up_but_unconfirmed')
+ end
+ end
+ end
+
+ def update
+ # This allows updating the e-mail without entering a password as is required
+ # on the account settings page; however, we only allow this for accounts
+ # that were not confirmed yet
+
+ if @user.update(user_params)
+ redirect_to auth_setup_path, notice: I18n.t('devise.confirmations.send_instructions')
+ else
+ render :show
+ end
+ end
+
+ helper_method :missing_email?
+
+ private
+
+ def require_unconfirmed_or_pending!
+ redirect_to root_path if current_user.confirmed? && current_user.approved?
+ end
+
+ def set_user
+ @user = current_user
+ end
+
+ def set_body_classes
+ @body_classes = 'lighter'
+ end
+
+ def user_params
+ params.require(:user).permit(:email)
+ end
+
+ def missing_email?
+ truthy_param?(:missing_email)
+ end
+end
diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb
index f3d23536694..fb8389034b9 100644
--- a/app/controllers/oauth/authorized_applications_controller.rb
+++ b/app/controllers/oauth/authorized_applications_controller.rb
@@ -7,6 +7,8 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
before_action :authenticate_resource_owner!
before_action :set_body_classes
+ skip_before_action :require_functional!
+
include Localized
def destroy
diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb
index dd19aadf636..97fe4d3281f 100644
--- a/app/controllers/settings/deletes_controller.rb
+++ b/app/controllers/settings/deletes_controller.rb
@@ -5,6 +5,9 @@ class Settings::DeletesController < Settings::BaseController
before_action :check_enabled_deletion
before_action :authenticate_user!
+ before_action :require_not_suspended!
+
+ skip_before_action :require_functional!
def show
@confirmation = Form::DeleteConfirmation.new
@@ -29,4 +32,8 @@ class Settings::DeletesController < Settings::BaseController
def delete_params
params.require(:form_delete_confirmation).permit(:password)
end
+
+ def require_not_suspended!
+ forbidden if current_account.suspended?
+ end
end
diff --git a/app/controllers/settings/sessions_controller.rb b/app/controllers/settings/sessions_controller.rb
index 84ebb21f2cc..df5ace80368 100644
--- a/app/controllers/settings/sessions_controller.rb
+++ b/app/controllers/settings/sessions_controller.rb
@@ -4,6 +4,8 @@ class Settings::SessionsController < Settings::BaseController
before_action :authenticate_user!
before_action :set_session, only: :destroy
+ skip_before_action :require_functional!
+
def destroy
@session.destroy!
flash[:notice] = I18n.t('sessions.revoke_success')
diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
index 02652a36c98..3145e092da7 100644
--- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
@@ -8,6 +8,8 @@ module Settings
before_action :authenticate_user!
before_action :ensure_otp_secret
+ skip_before_action :require_functional!
+
def new
prepare_two_factor_form
end
diff --git a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
index 874bf532ba5..09a759860e9 100644
--- a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
@@ -7,6 +7,8 @@ module Settings
before_action :authenticate_user!
+ skip_before_action :require_functional!
+
def create
@recovery_codes = current_user.generate_otp_backup_codes!
current_user.save!
diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb
index e12c4307468..6904076e424 100644
--- a/app/controllers/settings/two_factor_authentications_controller.rb
+++ b/app/controllers/settings/two_factor_authentications_controller.rb
@@ -7,6 +7,8 @@ module Settings
before_action :authenticate_user!
before_action :verify_otp_required, only: [:create]
+ skip_before_action :require_functional!
+
def show
@confirmation = Form::TwoFactorConfirmation.new
end
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index 373a1026035..f625bc13989 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -204,29 +204,6 @@ $content-width: 840px;
border: 0;
}
}
-
- .muted-hint {
- color: $darker-text-color;
-
- a {
- color: $highlight-text-color;
- }
- }
-
- .positive-hint {
- color: $valid-value-color;
- font-weight: 500;
- }
-
- .negative-hint {
- color: $error-value-color;
- font-weight: 500;
- }
-
- .neutral-hint {
- color: $dark-text-color;
- font-weight: 500;
- }
}
@media screen and (max-width: $no-columns-breakpoint) {
@@ -249,6 +226,41 @@ $content-width: 840px;
}
}
+hr.spacer {
+ width: 100%;
+ border: 0;
+ margin: 20px 0;
+ height: 1px;
+}
+
+.muted-hint {
+ color: $darker-text-color;
+
+ a {
+ color: $highlight-text-color;
+ }
+}
+
+.positive-hint {
+ color: $valid-value-color;
+ font-weight: 500;
+}
+
+.negative-hint {
+ color: $error-value-color;
+ font-weight: 500;
+}
+
+.neutral-hint {
+ color: $dark-text-color;
+ font-weight: 500;
+}
+
+.warning-hint {
+ color: $gold-star;
+ font-weight: 500;
+}
+
.filters {
display: flex;
flex-wrap: wrap;
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index 456ee4e0d3d..ac99124ea86 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -300,6 +300,13 @@ code {
}
}
+ .input.static .label_input__wrapper {
+ font-size: 16px;
+ padding: 10px;
+ border: 1px solid $dark-text-color;
+ border-radius: 4px;
+ }
+
input[type=text],
input[type=number],
input[type=email],
diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/omniauthable.rb
index 28303308395..b9c124841ba 100644
--- a/app/models/concerns/omniauthable.rb
+++ b/app/models/concerns/omniauthable.rb
@@ -43,7 +43,7 @@ module Omniauthable
# Check if the user exists with provided email if the provider gives us a
# verified email. If no verified email was provided or the user already