app/controllers/users/reset_passwords_controller.rb
# frozen_string_literal: true
module Users
class ResetPasswordsController < Devise::PasswordsController
include AuthorizationCountConcern
before_action :store_sp_metadata_in_session, only: [:edit]
before_action :store_token_in_session, only: [:edit]
def new
analytics.password_reset_visit
@password_reset_email_form = PasswordResetEmailForm.new('')
end
def create
@password_reset_email_form = PasswordResetEmailForm.new(email)
result = @password_reset_email_form.submit
analytics.password_reset_email(**result.to_h)
if result.success?
handle_valid_email
else
render :new
end
end
def edit
if params[:reset_password_token]
redirect_to edit_user_password_url
else
result = PasswordResetTokenValidator.new(token_user).submit
analytics.password_reset_token(**result.to_h)
if result.success?
@reset_password_form = ResetPasswordForm.new(build_user)
@forbidden_passwords = forbidden_passwords(token_user.email_addresses)
else
handle_invalid_or_expired_token(result)
end
end
end
# PUT /resource/password
def update
self.resource = user_matching_token(user_params[:reset_password_token])
@reset_password_form = ResetPasswordForm.new(resource)
result = @reset_password_form.submit(user_params)
analytics.password_reset_password(**result.to_h)
if result.success?
session.delete(:reset_password_token)
handle_successful_password_reset
else
handle_unsuccessful_password_reset(result)
end
end
protected
def store_sp_metadata_in_session
return if params[:request_id].blank?
StoreSpMetadataInSession.new(session:, request_id: params[:request_id]).call
bump_auth_count
end
def forbidden_passwords(email_addresses)
email_addresses.flat_map do |email_address|
ForbiddenPasswords.new(email_address.email).call
end
end
def email_params
params.require(:password_reset_email_form).permit(:email, :resend)
end
def email
email_params[:email]
end
def request_id
sp_session[:request_id]
end
def handle_valid_email
RequestPasswordReset.new(
email: email,
request_id: request_id,
analytics: analytics,
).perform
session[:email] = email
resend_confirmation = email_params[:resend]
redirect_to forgot_password_url(resend: resend_confirmation)
end
def store_token_in_session
return if session[:reset_password_token]
session[:reset_password_token] = params[:reset_password_token]
end
def handle_invalid_or_expired_token(result)
flash[:error] = t("devise.passwords.#{result.errors[:user].first}")
session.delete(:reset_password_token)
redirect_to new_user_password_url
end
def user_matching_token(token)
reset_password_token = Devise.token_generator.digest(User, :reset_password_token, token)
user = User.find_or_initialize_with_error_by(:reset_password_token, reset_password_token)
user.reset_password_token = token if user.reset_password_token?
user
end
def password_token
session[:reset_password_token] || params[:reset_password_token]
end
def token_user
@token_user ||= User.with_reset_password_token(password_token)
end
def build_user
User.new(reset_password_token: password_token)
end
def handle_successful_password_reset
send_password_reset_risc_event
create_reset_event_and_send_notification
flash[:info] = t('devise.passwords.updated_not_active') if is_flashing_format?
redirect_to new_user_session_url
end
def send_password_reset_risc_event
event = PushNotification::PasswordResetEvent.new(user: resource)
PushNotification::HttpPush.deliver(event)
end
def handle_unsuccessful_password_reset(result)
reset_password_token_errors = result.errors[:reset_password_token]
if reset_password_token_errors.present?
session.delete(:reset_password_token)
flash[:error] = t("devise.passwords.#{reset_password_token_errors.first}")
redirect_to new_user_password_url
return
end
@forbidden_passwords = forbidden_passwords(resource.email_addresses)
render :edit
end
def create_reset_event_and_send_notification
_event, disavowal_token = create_user_event_with_disavowal(:password_changed, resource)
UserAlerts::AlertUserAboutPasswordChange.call(resource, disavowal_token)
end
def user_params
params.require(:reset_password_form).
permit(:password, :password_confirmation, :reset_password_token)
end
def assert_reset_token_passed
# remove devise's default behavior
end
end
end