SECURITY: Support for confirm old as well as new email accounts

This commit is contained in:
Robin Ward
2016-03-07 14:40:11 -05:00
parent d62689fa76
commit 5771d2aee2
47 changed files with 454 additions and 114 deletions

View File

@@ -20,7 +20,8 @@ class Admin::EmailTemplatesController < Admin::AdminController
"system_messages.unblocked", "system_messages.user_automatically_blocked",
"system_messages.welcome_invite", "system_messages.welcome_user", "test_mailer",
"user_notifications.account_created", "user_notifications.admin_login",
"user_notifications.authorize_email", "user_notifications.forgot_password",
"user_notifications.confirm_new_email", "user_notifications.confirm_old_email",
"user_notifications.notify_old_email", "user_notifications.forgot_password",
"user_notifications.set_password", "user_notifications.signup",
"user_notifications.signup_after_approval",
"user_notifications.user_invited_to_private_message_pm",

View File

@@ -5,7 +5,7 @@ require_dependency 'rate_limiter'
class UsersController < ApplicationController
skip_before_filter :authorize_mini_profiler, only: [:avatar]
skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :account_created, :activate_account, :perform_account_activation, :authorize_email, :user_preferences_redirect, :avatar, :my_redirect, :toggle_anon, :admin_login]
skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :account_created, :activate_account, :perform_account_activation, :user_preferences_redirect, :avatar, :my_redirect, :toggle_anon, :admin_login]
before_filter :ensure_logged_in, only: [:username, :update, :user_preferences_redirect, :upload_user_image, :pick_avatar, :destroy_user_image, :destroy, :check_emails]
before_filter :respond_to_suspicious_request, only: [:create]
@@ -21,7 +21,6 @@ class UsersController < ApplicationController
:activate_account,
:perform_account_activation,
:send_activation_email,
:authorize_email,
:password_reset,
:confirm_email_token,
:admin_login]
@@ -471,16 +470,6 @@ class UsersController < ApplicationController
end
end
def authorize_email
expires_now()
if @user = EmailToken.confirm(params[:token])
log_on_user(@user)
else
flash[:error] = I18n.t('change_email.error')
end
render layout: 'no_ember'
end
def account_created
@message = session['user_created_message'] || I18n.t('activation.missing_session')
expires_now

View File

@@ -1,9 +1,13 @@
require_dependency 'rate_limiter'
require_dependency 'email_validator'
require_dependency 'email_updater'
class UsersEmailController < ApplicationController
before_filter :ensure_logged_in
before_filter :ensure_logged_in, only: [:index, :update]
skip_before_filter :check_xhr, only: [:confirm]
skip_before_filter :redirect_to_login_if_required, only: [:confirm]
def index
end
@@ -11,31 +15,32 @@ class UsersEmailController < ApplicationController
def update
params.require(:email)
user = fetch_user_from_params
guardian.ensure_can_edit_email!(user)
lower_email = Email.downcase(params[:email]).strip
RateLimiter.new(user, "change-email-hr-#{request.remote_ip}", 6, 1.hour).performed!
RateLimiter.new(user, "change-email-min-#{request.remote_ip}", 3, 1.minute).performed!
EmailValidator.new(attributes: :email).validate_each(user, :email, lower_email)
return render_json_error(user.errors.full_messages) if user.errors[:email].present?
updater = EmailUpdater.new(guardian, user)
updater.change_to(params[:email])
# Raise an error if the email is already in use
return render_json_error(I18n.t('change_email.error')) if User.find_by_email(lower_email)
email_token = user.email_tokens.create(email: lower_email)
Jobs.enqueue(
:user_email,
to_address: lower_email,
type: :authorize_email,
user_id: user.id,
email_token: email_token.token
)
if updater.errors.present?
return render_json_error(updater.errors.full_messages)
end
render nothing: true
rescue RateLimiter::LimitExceeded
render_json_error(I18n.t("rate_limiter.slow_down"))
end
def confirm
expires_now
updater = EmailUpdater.new
@update_result = updater.confirm(params[:token])
# Log in the user if the process is complete (and they're not logged in)
log_on_user(updater.user) if @update_result == :complete
render layout: 'no_ember'
end
end