Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/controllers/account_reset/confirm_request_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ def show
if email.blank?
redirect_to root_url
else
render :show, locals: { email: email }
render :show, locals: {
email: email, sms_phone: SmsLoginOptionPolicy.new(current_user).configured?
}
sign_out
end
end
end
Expand Down
49 changes: 19 additions & 30 deletions app/controllers/account_reset/request_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ class RequestController < ApplicationController
before_action :confirm_two_factor_enabled
before_action :confirm_user_not_verified

def show; end
def show
analytics.track_event(Analytics::ACCOUNT_RESET_VISIT)
end

def create
analytics.track_event(Analytics::ACCOUNT_RESET, event: :request)
create_request
send_notifications
reset_session_with_email
analytics.track_event(Analytics::ACCOUNT_RESET, analytics_attributes)
AccountReset::CreateRequest.new(current_user).call
flash[:email] = current_user.email
redirect_to account_reset_confirm_request_url
end

Expand All @@ -22,36 +23,24 @@ def check_account_reset_enabled
redirect_to root_url unless FeatureManagement.account_reset_enabled?
end

def confirm_user_not_verified
# IAL2 users should not be able to reset account to comply with AAL2 reqs
redirect_to account_url if decorated_user.identity_verified?
end

def reset_session_with_email
email = current_user.email
sign_out
flash[:email] = email
end
def confirm_two_factor_enabled
return if current_user.two_factor_enabled?

def send_notifications
phone = current_user.phone
if phone
SmsAccountResetNotifierJob.perform_now(
phone: phone,
cancel_token: current_user.account_reset_request.request_token
)
end
UserMailer.account_reset_request(current_user).deliver_later
redirect_to two_factor_options_url
end

def create_request
AccountResetService.new(current_user).create_request
def confirm_user_not_verified
# IAL2 users should not be able to reset account to comply with AAL2 reqs
redirect_to account_url if decorated_user.identity_verified?
end

def confirm_two_factor_enabled
return if current_user.two_factor_enabled?

redirect_to phone_setup_url
def analytics_attributes
{
event: 'request',
sms_phone: SmsLoginOptionPolicy.new(current_user).configured?,
totp: AuthAppLoginOptionPolicy.new(current_user).configured?,
piv_cac: PivCacLoginOptionPolicy.new(current_user).configured?,
}
end
end
end
4 changes: 2 additions & 2 deletions app/jobs/sms_account_reset_notifier_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ class SmsAccountResetNotifierJob < ApplicationJob
queue_as :sms
include Rails.application.routes.url_helpers

def perform(phone:, cancel_token:)
def perform(phone:, token:)
TwilioService::Utils.new.send_sms(
to: phone,
body: I18n.t(
'jobs.sms_account_reset_notifier_job.message',
app: APP_NAME,
cancel_link: account_reset_cancel_url(token: cancel_token)
cancel_link: account_reset_cancel_url(token: token)
)
)
end
Expand Down
41 changes: 41 additions & 0 deletions app/services/account_reset/create_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module AccountReset
class CreateRequest
def initialize(user)
@user = user
end

def call
create_request
notify_user_by_email
notify_user_by_sms_if_applicable
end

private

attr_reader :user

def create_request
request = AccountResetRequest.find_or_create_by(user: user)
request.update!(
request_token: SecureRandom.uuid,
requested_at: Time.zone.now,
cancelled_at: nil,
granted_at: nil,
granted_token: nil
)
end

def notify_user_by_email
UserMailer.account_reset_request(user).deliver_later
end

def notify_user_by_sms_if_applicable
phone = user.phone
return unless phone
SmsAccountResetNotifierJob.perform_now(
phone: phone,
token: user.account_reset_request.request_token
)
end
end
end
9 changes: 0 additions & 9 deletions app/services/account_reset_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@ def initialize(user)
@user_id = user.id
end

def create_request
account_reset = account_reset_request
account_reset.update(request_token: SecureRandom.uuid,
requested_at: Time.zone.now,
cancelled_at: nil,
granted_at: nil,
granted_token: nil)
end

def self.report_fraud(token)
account_reset = token.blank? ? nil : AccountResetRequest.find_by(request_token: token)
return false unless account_reset
Expand Down
1 change: 1 addition & 0 deletions app/services/analytics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def browser
# rubocop:disable Metrics/LineLength
ACCOUNT_RESET = 'Account Reset'.freeze
ACCOUNT_DELETION = 'Account Deletion Requested'.freeze
ACCOUNT_RESET_VISIT = 'Account deletion and reset visited'.freeze
ACCOUNT_VISIT = 'Account Page Visited'.freeze
EMAIL_AND_PASSWORD_AUTH = 'Email and Password Authentication'.freeze
EMAIL_CHANGE_REQUEST = 'Email Change Request'.freeze
Expand Down
5 changes: 5 additions & 0 deletions app/views/account_reset/confirm_request/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
h1.mt1.mb-12p.h3 = t('headings.verify_email')
p
== t('account_reset.confirm_request.instructions', email: email)
- if sms_phone
p
== t('account_reset.confirm_request.security_note')
p
== t('account_reset.confirm_request.close_window')
5 changes: 3 additions & 2 deletions config/locales/account_reset/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ en:
title: You have deleted your account
confirm_request:
check_your_email: Check your email
close_window: You can close this window if you're done.
instructions: We sent an email to <strong>%{email}</strong> to begin the account
delete process. Follow the instructions in your email to complete the process.
<br><br> As a security measure, we also sent a text to your registered phone
number. <br><br> You can close this window if you are done.
security_note: As a security measure, we also sent a text to your registered
phone number.
delete_account:
are_you_sure: Are you sure you want to delete your account?
cancel: Cancel
Expand Down
7 changes: 4 additions & 3 deletions config/locales/account_reset/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ es:
title: Has eliminado tu cuenta
confirm_request:
check_your_email: Consultar su correo electrónico
close_window: Puede cerrar esta ventana si ha terminado.
instructions: Enviamos un correo electrónico a <strong>%{email}</strong> para
comenzar el proceso de eliminación de cuenta. Siga las instrucciones en su
correo electrónico para completar el proceso.<br><br>Como medida de seguridad,
también enviamos un mensaje de texto a su registro número de teléfono.<br><br>
Puede cerrar esta ventana si ha terminado.
correo electrónico para completar el proceso.
security_note: Como medida de seguridad, también enviamos un mensaje de texto
a su registro número de teléfono.
delete_account:
are_you_sure: "¿Seguro que quieres eliminar tu cuenta?"
cancel: Cancelar
Expand Down
7 changes: 4 additions & 3 deletions config/locales/account_reset/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ fr:
title: Vous avez supprimé votre compte
confirm_request:
check_your_email: Vérifiez votre email
close_window: Vous pouvez fermer cette fenêtre si vous avez terminé.
instructions: Nous avons envoyé un e-mail à <strong>%{email}</strong> pour commencer
le compte. Supprimer le processus. Suivez les instructions dans votre e-mail
pour terminer le processus.<br> <br>Par mesure de sécurité, nous avons également
envoyé un SMS sur votre téléphone enregistré nombre. <br> <br> Vous pouvez
fermer cette fenêtre si vous avez terminé.
pour terminer le processus.
security_note: Par mesure de sécurité, nous avons également envoyé un SMS à
votre numéro de téléphone enregistré.
delete_account:
are_you_sure: Êtes-vous sûr de vouloir supprimer votre compte?
cancel: Annuler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@

RSpec.describe AccountReset::ConfirmRequestController do
describe '#show' do
context 'email in session' do
it 'renders the page and deletes the email from the session' do
allow(controller).to receive(:flash).and_return(email: 'test@example.com')

get :show

expect(response).to render_template(:show)
end
end

context 'no email in session' do
context 'no email in flash' do
it 'redirects to the new user registration path' do
get :show

Expand Down
10 changes: 6 additions & 4 deletions spec/controllers/account_reset/delete_account_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
require 'rails_helper'

describe AccountReset::DeleteAccountController do
include AccountResetHelper

describe '#delete' do
it 'logs a good token to the analytics' do
user = create(:user)
AccountResetService.new(user).create_request
create_account_reset_request_for(user)
AccountResetService.new(user).grant_request

session[:granted_token] = AccountResetRequest.all[0].granted_token
Expand Down Expand Up @@ -33,7 +35,7 @@
describe '#show' do
it 'prevents parameter leak' do
user = create(:user)
AccountResetService.new(user).create_request
create_account_reset_request_for(user)
AccountResetService.new(user).grant_request

get :show, params: { token: AccountResetRequest.all[0].granted_token }
Expand All @@ -49,7 +51,7 @@

it 'renders the page' do
user = create(:user)
AccountResetService.new(user).create_request
create_account_reset_request_for(user)
AccountResetService.new(user).grant_request
session[:granted_token] = AccountResetRequest.all[0].granted_token

Expand All @@ -60,7 +62,7 @@

it 'displays a flash and redirects to root if the token is expired' do
user = create(:user)
AccountResetService.new(user).create_request
create_account_reset_request_for(user)
AccountResetService.new(user).grant_request

stub_analytics
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
require 'rails_helper'

describe AccountReset::ReportFraudController do
include AccountResetHelper

describe '#update' do
it 'logs a good token to the analytics' do
user = create(:user)
AccountResetService.new(user).create_request
create_account_reset_request_for(user)

stub_analytics
expect(@analytics).to receive(:track_event).
Expand Down
Loading