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
21 changes: 21 additions & 0 deletions app/controllers/sign_up/cancellations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module SignUp
class CancellationsController < ApplicationController
before_action :ensure_in_setup

def new
properties = ParseControllerFromReferer.new(request.referer).call
analytics.track_event(Analytics::USER_REGISTRATION_CANCELLATION, properties)
@presenter = CancellationPresenter.new(view_context: view_context)
end

private

def ensure_in_setup
redirect_to root_url if !session[:user_confirmation_token] && two_factor_enabled
end

def two_factor_enabled
current_user && MfaPolicy.new(current_user).two_factor_enabled?
end
end
end
10 changes: 10 additions & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class UsersController < ApplicationController
Copy link
Copy Markdown
Contributor

@jmhooper jmhooper Dec 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this change, but worth noting that moving this into the account reset namespace may be a good refactor. Confusing to have this controller out here, makes you think this is the controller for the "delete account" button on the account page.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I'm misreading this. This is actually for cancelling during account setup, ignore the above

before_action :ensure_in_setup

def destroy
track_account_deletion_event
url_after_cancellation = decorated_session.cancel_link_url
Expand All @@ -19,4 +21,12 @@ def destroy_user
user&.destroy!
sign_out if user
end

def ensure_in_setup
redirect_to root_url if !session[:user_confirmation_token] && two_factor_enabled
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we checking for the user confirmation token in the session? What happens if we remove that here?

Copy link
Copy Markdown
Contributor Author

@stevegsa stevegsa Dec 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two_factor_enabled needs to have a user but in the password screen it won't have one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(password setup)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally figured this out and posted some suggestions that may make this easier to follow in Slack. Those are take it or leave it though.

end

def two_factor_enabled
current_user && MfaPolicy.new(current_user).two_factor_enabled?
end
end
48 changes: 48 additions & 0 deletions app/presenters/cancellation_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class CancellationPresenter < FailurePresenter
include ActionView::Helpers::TranslationHelper
include Rails.application.routes.url_helpers

delegate :request, to: :view_context

attr_reader :view_context

def initialize(view_context:)
super(:warning)
@view_context = view_context
end

def title
t('headings.cancellations.prompt')
end

def header
t('headings.cancellations.prompt')
end

def cancellation_warnings
[
t('users.delete.bullet_1', app: APP_NAME),
t('users.delete.bullet_2_loa1'),
t('users.delete.bullet_3', app: APP_NAME),
]
end

def go_back_path
referer_path || two_factor_options_path
end

private

def referer_path
referer_string = request.env['HTTP_REFERER']
return if referer_string.blank?
referer_uri = URI.parse(referer_string)
return if referer_uri.scheme == 'javascript'
return unless referer_uri.host == Figaro.env.domain_name.split(':')[0]
extract_path_and_query_from_uri(referer_uri)
end

def extract_path_and_query_from_uri(uri)
[uri.path, uri.query].compact.join('?')
end
end
1 change: 1 addition & 0 deletions app/services/analytics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def browser
TWILIO_SMS_INBOUND_MESSAGE_VALIDATION_FAILED = 'Twilio SMS Inbound Validation Failed'.freeze
USER_REGISTRATION_AGENCY_HANDOFF_PAGE_VISIT = 'User registration: agency handoff visited'.freeze
USER_REGISTRATION_AGENCY_HANDOFF_COMPLETE = 'User registration: agency handoff complete'.freeze
USER_REGISTRATION_CANCELLATION = 'User registration: cancellation visited'.freeze
USER_REGISTRATION_EMAIL = 'User Registration: Email Submitted'.freeze
USER_REGISTRATION_EMAIL_CONFIRMATION = 'User Registration: Email Confirmation'.freeze
USER_REGISTRATION_EMAIL_CONFIRMATION_RESEND = 'User Registration: Email Confirmation requested due to invalid token'.freeze
Expand Down
6 changes: 1 addition & 5 deletions app/views/shared/_cancel.html.slim
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
- cancel = sign_up_or_idv_no_js_link || link
- other_cancel = link || decorated_session&.sp_return_url || profile_path

.mt2.pt1.border-top
- if user_signing_up?
- method = user_signing_up? ? :delete : :get

= button_to cancel_link_text, cancel, method: method,
class: 'btn btn-link', id: 'auth-flow-cancel'
= button_to cancel_link_text, sign_up_cancel_path, method: :get, class: 'btn btn-link'
= render 'shared/cancel_action_modal',
idv: user_verifying_identity?,
user_signing_up: user_signing_up?
Expand Down
12 changes: 12 additions & 0 deletions app/views/sign_up/cancellations/new.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
= render 'shared/failure', presenter: @presenter

p.mb1.bold = t('sign_up.cancel.warning_header')

ul class="list-reset #{@presenter.state_color}-dots"
- @presenter.cancellation_warnings.each do |warning|
li = warning

.mt3 = button_to t('forms.buttons.cancel'), destroy_user_path,
method: :delete, class: 'btn btn-primary sm-col-6 col-12 btn-wide'
.mt2 = link_to t('links.go_back'), @presenter.go_back_path,
class: 'btn btn-secondary sm-col-6 col-12 btn-wide'
5 changes: 2 additions & 3 deletions config/locales/users/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ en:
actions:
cancel: Cancel and return to your profile
delete: Delete account
bullet_1: You won't have a %{app} account.
bullet_2_loa1: "%{app} will delete your email address, password, and phone number
from our system."
bullet_1: You won't have a %{app} account
bullet_2_loa1: We'll delete your email address, password, and phone number
bullet_2_loa3: "%{app} will delete your email address, password, phone number,
name, address, date of birth and Social Security number from our system."
bullet_3: You won't be able to securely access your information using %{app}.
Expand Down
4 changes: 2 additions & 2 deletions config/locales/users/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ es:
cancel: Anular y regresar a su perfil
delete: Eliminar cuenta
bullet_1: Usted no tendrá una %{app} cuenta.
bullet_2_loa1: "%{app} borrará su email, contraseña y número de teléfono de
nuestro sistema."
bullet_2_loa1: Eliminaremos su dirección de correo electrónico, contraseña y
número de teléfono
bullet_2_loa3: "%{app} borrará su email, contraseña, número de teléfono, nombre,
dirección, fecha de nacimiento y número de Seguro Social de nuestro sistema."
bullet_3: Usted no podrá tener acceso seguro a su información usando %{app}
Expand Down
4 changes: 2 additions & 2 deletions config/locales/users/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ fr:
cancel: Annuler et retourner à votre profil
delete: Supprimer le compte
bullet_1: Vous n'aurez pas de compte %{app}.
bullet_2_loa1: "%{app} supprimera votre adresse e-mail, votre mot de passe et
votre numéro de téléphone de notre système."
bullet_2_loa1: Nous effacerons votre adresse email, votre mot de passe et votre
numéro de téléphone
bullet_2_loa3: "%{app} supprimera votre adresse e-mail, votre mot de passe et
votre numéro de téléphone, votre nom, votre adresse, votre date de naissance
et votre numéro de sécurité sociale de notre système."
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@
get '/sign_up/verify_email' => 'sign_up/emails#show', as: :sign_up_verify_email
get '/sign_up/completed' => 'sign_up/completions#show', as: :sign_up_completed
post '/sign_up/completed' => 'sign_up/completions#update'
get '/sign_up/cancel/' => 'sign_up/cancellations#new', as: :sign_up_cancel
delete '/sign_up/cancel' => 'sign_up/cancellations#destroy'

match '/sign_out' => 'sign_out#destroy', via: %i[get post delete]

Expand Down
30 changes: 30 additions & 0 deletions spec/controllers/sign_up/cancellations_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'rails_helper'

describe SignUp::CancellationsController do
describe '#new' do
it 'tracks the event in analytics when referer is nil' do
stub_sign_in
stub_analytics
properties = { request_came_from: 'no referer' }

expect(@analytics).to receive(:track_event).with(
Analytics::USER_REGISTRATION_CANCELLATION, properties
)

get :new
end

it 'tracks the event in analytics when referer is present' do
stub_sign_in
stub_analytics
request.env['HTTP_REFERER'] = 'http://example.com/'
properties = { request_came_from: 'users/sessions#new' }

expect(@analytics).to receive(:track_event).with(
Analytics::USER_REGISTRATION_CANCELLATION, properties
)

get :new
end
end
end
13 changes: 13 additions & 0 deletions spec/controllers/users_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,25 @@

it 'destroys the current user and redirects to sign in page, with a helpful flash message' do
sign_in_as_user
subject.session[:user_confirmation_token] = '1'

expect { delete :destroy }.to change(User, :count).by(-1)
expect(response).to redirect_to(root_url)
expect(flash.now[:success]).to eq t('sign_up.cancel.success')
end

it 'does not destroy the user if the user is not in setup mode and is after 2fa' do
sign_in_as_user

expect { delete :destroy }.to change(User, :count).by(0)
end

it 'does not destroy the user if the user is not in setup mode and is before 2fa' do
sign_in_before_2fa

expect { delete :destroy }.to change(User, :count).by(0)
end

it 'finds the proper user and removes their record without `current_user`' do
confirmation_token = '1'

Expand Down
21 changes: 19 additions & 2 deletions spec/features/saml/loa1/account_creation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,30 @@
it 'redirects to the branded start page' do
authn_request = auth_request.create(saml_settings)
visit authn_request
sp_request_id = ServiceProviderRequest.last.uuid
click_link t('sign_up.registrations.create_account')
submit_form_with_valid_email
click_confirmation_link_in_email('test@test.com')
click_button t('links.cancel_account_creation')

expect(current_url).to eq sign_up_start_url(request_id: sp_request_id)
expect(current_url).to eq sign_up_cancel_url

click_button t('forms.buttons.cancel')
expect(current_url).to eq sign_up_start_url(request_id: ServiceProviderRequest.last.uuid)
end

it 'redirects to the password page after cancelling the cancellation' do
authn_request = auth_request.create(saml_settings)
visit authn_request
click_link t('sign_up.registrations.create_account')
submit_form_with_valid_email
click_confirmation_link_in_email('test@test.com')
previous_url = current_url
click_button t('links.cancel_account_creation')

expect(current_url).to eq sign_up_cancel_url

click_link t('links.go_back')
expect(current_url).to eq previous_url
end
end
end
37 changes: 2 additions & 35 deletions spec/features/users/sign_up_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
end

context 'user cancels on the enter password screen', email: true do
it 'returns them to the home page' do
it 'sends them to the cancel page' do
email = 'test@test.com'

visit sign_up_email_path
Expand All @@ -36,7 +36,7 @@

click_on t('links.cancel_account_creation')

expect(current_path).to eq root_path
expect(current_path).to eq sign_up_cancel_path
end
end

Expand Down Expand Up @@ -64,39 +64,6 @@
end

context 'with js', js: true do
context 'sp loa1' do
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good riddance

it 'allows the user to toggle the modal' do
begin_sign_up_with_sp_and_loa(loa3: false)
expect(page).not_to have_xpath("//div[@id='cancel-action-modal']")

click_on t('links.cancel')
expect(page).to have_xpath("//div[@id='cancel-action-modal']")

click_on t('sign_up.buttons.continue')
expect(page).not_to have_xpath("//div[@id='cancel-action-modal']")
end

it 'allows the user to delete their account and returns them to the branded start page' do
user = begin_sign_up_with_sp_and_loa(loa3: false)

click_on t('links.cancel')
click_on t('sign_up.buttons.cancel')

expect(page).to have_current_path(sign_up_start_path(request_id: '123'))
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
end
end

context 'sp loa3' do
it 'behaves like loa1 when user has not finished sign up' do
begin_sign_up_with_sp_and_loa(loa3: true)

click_on t('links.cancel')

expect(page).to have_xpath("//input[@value=\"#{t('sign_up.buttons.cancel')}\"]")
end
end

context 'user enters their email as their password', email: true do
it 'treats it as a weak password' do
email = 'test@test.com'
Expand Down
62 changes: 62 additions & 0 deletions spec/presenters/cancellation_presenter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'rails_helper'

describe CancellationPresenter do
let(:good_url) { 'http://example.com/asdf/qwerty' }
let(:good_url_with_path) { 'http://example.com/asdf?qwerty=123' }
let(:bad_url) { 'http://evil.com/asdf/qwerty' }

let(:view_context) { ActionView::Base.new }

subject { described_class.new(view_context: view_context) }

describe '#go_back_link' do
let(:sign_up_path) { '/two_factor_options' }

before do
allow(view_context).to receive(:sign_up_path).and_return(sign_up_path)
request = instance_double(ActionDispatch::Request)
allow(request).to receive(:env).and_return('HTTP_REFERER' => referer_header)
allow(view_context).to receive(:request).and_return(request)
end

context 'without a referer header' do
let(:referer_header) { nil }

it 'returns the sign_up_path' do
expect(subject.go_back_path).to eq(sign_up_path)
end
end

context 'with a referer header' do
let(:referer_header) { 'http://www.example.com/asdf/qwerty' }

it 'returns the path' do
expect(subject.go_back_path).to eq('/asdf/qwerty')
end
end

context 'with a referer header with query params' do
let(:referer_header) { 'http://www.example.com/asdf?qwerty=123' }

it 'returns the path with the query params' do
expect(subject.go_back_path).to eq('/asdf?qwerty=123')
end
end

context 'with a referer header for a different domain' do
let(:referer_header) { 'http://www.evil.com/asdf/qwerty' }

it 'returns the sign_up_path' do
expect(subject.go_back_path).to eq(sign_up_path)
end
end

context 'with a referer header with a javascript scheme' do
let(:referer_header) { 'javascript://do-some-evil-stuff' }

it 'returns the sign_up_path' do
expect(subject.go_back_path).to eq(sign_up_path)
end
end
end
end