diff --git a/app/assets/stylesheets/components/_util.scss b/app/assets/stylesheets/components/_util.scss index 3e52e2c8bb4..26b80beb1f0 100644 --- a/app/assets/stylesheets/components/_util.scss +++ b/app/assets/stylesheets/components/_util.scss @@ -19,6 +19,17 @@ vertical-align: middle; } + +.block-center { + margin: 0 auto; +} + +.scale-down { + // trigger anti-aliasing in chrome + backface-visibility: hidden; + transform: scale(.7); +} + @media #{$breakpoint-sm} { // scss-lint:disable ImportantRule .sm-display-inline-block { display: inline-block !important; } diff --git a/app/controllers/concerns/two_factor_authenticatable.rb b/app/controllers/concerns/two_factor_authenticatable.rb index 24fd78f0851..73f0761a1a2 100644 --- a/app/controllers/concerns/two_factor_authenticatable.rb +++ b/app/controllers/concerns/two_factor_authenticatable.rb @@ -186,7 +186,7 @@ def after_otp_action_path elsif @updating_existing_number account_path elsif decorated_user.password_reset_profile.present? - reactivate_account_path + manage_reactivate_account_path else account_path end diff --git a/app/controllers/reactivate_account_controller.rb b/app/controllers/reactivate_account_controller.rb new file mode 100644 index 00000000000..c8e43c8b85f --- /dev/null +++ b/app/controllers/reactivate_account_controller.rb @@ -0,0 +1,20 @@ +class ReactivateAccountController < ApplicationController + before_action :confirm_two_factor_authenticated + before_action :confirm_password_reset_profile + + def index + user_session[:acknowledge_personal_key] ||= true + end + + def update + user_session.delete(:acknowledge_personal_key) + redirect_to verify_url + end + + protected + + def confirm_password_reset_profile + return if current_user.decorate.password_reset_profile + redirect_to root_url + end +end diff --git a/app/controllers/verify_controller.rb b/app/controllers/verify_controller.rb index d02d8738cca..aa9452e8c13 100644 --- a/app/controllers/verify_controller.rb +++ b/app/controllers/verify_controller.rb @@ -3,6 +3,7 @@ class VerifyController < ApplicationController before_action :confirm_two_factor_authenticated before_action :confirm_idv_needed, only: %i[cancel fail] + before_action :profile_needs_reactivation?, only: [:index] def index if active_profile? @@ -26,6 +27,15 @@ def fail private + def profile_needs_reactivation? + return unless password_reset_profile && user_session[:acknowledge_personal_key] == true + redirect_to manage_reactivate_account_url + end + + def password_reset_profile + current_user.decorate.password_reset_profile + end + def active_profile? current_user.active_profile.present? end diff --git a/app/views/reactivate_account/index.html.slim b/app/views/reactivate_account/index.html.slim new file mode 100644 index 00000000000..845f0f0b6aa --- /dev/null +++ b/app/views/reactivate_account/index.html.slim @@ -0,0 +1,22 @@ +- title t('titles.reactivate_account') + +h1.h3.mt0.mb2 = t('headings.account.reactivate') + +p.mb4 = t('instructions.account.reactivate.intro') + +h2.h4.pb1.border-bottom = t('instructions.account.reactivate.begin') + +h3.fs-20p.sans-serif.mt4 = t('instructions.account.reactivate.with_key') + +p.mb0 = t('instructions.account.reactivate.explanation') + +.scale-down + = render 'partials/personal_key/key', code: 'XXXX-XXXX-XXXX-XXXX' + +.block-center.center.col-10 + .col-12.mb2 + = link_to t('links.account.reactivate.with_key'), reactivate_account_path, + class: 'btn btn-primary block' + = form_tag manage_reactivate_account_path, method: :put, class: 'col-12' do + = button_tag t('links.account.reactivate.without_key'), type: 'submit', + class: 'btn btn-secondary block col-12' diff --git a/app/views/users/reactivate_account/index.html.slim b/app/views/users/reactivate_account/index.html.slim index 555995a36f6..d56954d0e6d 100644 --- a/app/views/users/reactivate_account/index.html.slim +++ b/app/views/users/reactivate_account/index.html.slim @@ -1,4 +1,4 @@ -- title t('titles.reactivate_profile') +- title t('titles.reactivate_account') h1.h3.my0 = t('forms.reactivate_profile.title') p.mt-tiny.mb0 = t('forms.reactivate_profile.instructions') diff --git a/config/locales/headings/en.yml b/config/locales/headings/en.yml index 9c922b03e5e..d1cf87dadb9 100644 --- a/config/locales/headings/en.yml +++ b/config/locales/headings/en.yml @@ -18,6 +18,7 @@ en: account_history: Account history login_info: Your account profile_info: Profile information + reactivate: Reactivate your account two_factor: Two-factor authentication verified_account: Verified Account personal_key: Here is your personal key diff --git a/config/locales/headings/es.yml b/config/locales/headings/es.yml index ebdd31c67ca..dd431a09d86 100644 --- a/config/locales/headings/es.yml +++ b/config/locales/headings/es.yml @@ -18,6 +18,7 @@ es: account_history: La historia de la cuenta login_info: Información de la cuenta profile_info: NOT TRANSLATED YET + reactivate: NOT TRANSLATED YET two_factor: Autenticación de dos factores verified_account: Cuenta verificada personal_key: Asegúrese de que siempre puede iniciar sesión diff --git a/config/locales/instructions/en.yml b/config/locales/instructions/en.yml index e70b128185d..320ba4a18fa 100644 --- a/config/locales/instructions/en.yml +++ b/config/locales/instructions/en.yml @@ -17,6 +17,16 @@ en: %{resend_code_link} fallback_html: If you can't take a phone call right now, you can %{link} wrong_number_html: Entered the wrong phone number? %{link} + account: + reactivate: + begin: Let's get started. + explanation: > + When you created your account, we gave you a list of words and asked + you to store them in a safe place. It looked similar to this: + intro: > + We take extra steps to keep your personal information secure and private, + so resetting your password takes a little extra effort. + with_key: Do you have your personal key? forgot_password: close_window: You can close this browser window once you have reset your password. password: @@ -28,7 +38,7 @@ en: phrases. Also avoid repeating passwords from other online accounts such as banks, email and social media. info: - lead: > + lead: > It must be at least %{min_length} characters long and not be a commonly used password. That's it! strength: diff --git a/config/locales/instructions/es.yml b/config/locales/instructions/es.yml index 93937aff8e2..89798cec450 100644 --- a/config/locales/instructions/es.yml +++ b/config/locales/instructions/es.yml @@ -15,6 +15,12 @@ es: confirm_code_html: NOT TRANSLATED YET fallback_html: NOT TRANSLATED YET wrong_number_html: ¿Ha ingresado el número de teléfono equivocado? %{link} + account: + reactivate: + begin: NOT TRANSLATED YET + explanation: NOT TRANSLATED YET + intro: NOT TRANSLATED YET + with_key: NOT TRANSLATED YET forgot_password: close_window: Puede cerrar esta ventana del navegador despues que haya restablecido su contraseña. password: diff --git a/config/locales/links/en.yml b/config/locales/links/en.yml index 478b0a5eb85..be0a5af5ebc 100644 --- a/config/locales/links/en.yml +++ b/config/locales/links/en.yml @@ -1,6 +1,10 @@ --- en: links: + account: + reactivate: + with_key: I have my key + without_key: I don't have my key back_to_sp: Back to %{sp} contact: Contact copy: Copy diff --git a/config/locales/links/es.yml b/config/locales/links/es.yml index 9838dabd55a..4e6f377c099 100644 --- a/config/locales/links/es.yml +++ b/config/locales/links/es.yml @@ -1,6 +1,10 @@ --- es: links: + account: + reactivate: + with_key: NOT TRANSLATED YET + without_key: NOT TRANSLATED YET back_to_sp: "Volver a %{sp}" contact: Contactar copy: NOT TRANSLATED YET diff --git a/config/locales/titles/en.yml b/config/locales/titles/en.yml index d591702a414..e723b867945 100644 --- a/config/locales/titles/en.yml +++ b/config/locales/titles/en.yml @@ -15,7 +15,7 @@ en: confirm: Confirm the password for your account forgot: Reset the password for your account account: Account - reactivate_profile: Reactivate profile + reactivate_account: Reactivate your account personal_key: Just in case registrations: new: Sign up for a account diff --git a/config/locales/titles/es.yml b/config/locales/titles/es.yml index a40ced78c7f..3808dc22116 100644 --- a/config/locales/titles/es.yml +++ b/config/locales/titles/es.yml @@ -15,7 +15,7 @@ es: confirm: NOT TRANSLATED YET forgot: NOT TRANSLATED YET account: NOT TRANSLATED YET - reactivate_profile: NOT TRANSLATED YET + reactivate_account: NOT TRANSLATED YET personal_key: NOT TRANSLATED YET registrations: new: NOT TRANSLATED YET diff --git a/config/routes.rb b/config/routes.rb index 2feecce8ef1..9f4ab0e068a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -47,6 +47,8 @@ get '/account' => 'accounts#show' get '/account/reactivate' => 'users/reactivate_account#index', as: :reactivate_account post '/account/reactivate' => 'users/reactivate_account#create' + get '/account/reactivate/start' => 'reactivate_account#index', as: :manage_reactivate_account + put '/account/reactivate/start' => 'reactivate_account#update' get '/account/verify_phone' => 'users/verify_profile_phone#index', as: :verify_profile_phone post '/account/verify_phone' => 'users/verify_profile_phone#create' diff --git a/spec/controllers/reactivate_account_controller_spec.rb b/spec/controllers/reactivate_account_controller_spec.rb new file mode 100644 index 00000000000..b88d9593cb2 --- /dev/null +++ b/spec/controllers/reactivate_account_controller_spec.rb @@ -0,0 +1,54 @@ +require 'rails_helper' + +describe ReactivateAccountController do + let(:user) { create(:user, profiles: profiles) } + let(:profiles) { [] } + + before { stub_sign_in(user) } + + describe 'before_actions' do + it 'requires the user to be logged in' do + expect(subject).to have_actions( + :confirm_two_factor_authenticated + ) + end + end + + describe '#index' do + context 'with a password reset profile' do + let(:profiles) { [create(:profile, deactivation_reason: :password_reset)] } + + it 'renders the index template' do + get :index + + expect(subject).to render_template(:index) + end + + it 'sets a key on the user session for future redirect guidance' do + get :index + + expect(subject.user_session[:acknowledge_personal_key]).to eq true + end + end + + context 'wthout a password reset profile' do + let(:profiles) { [create(:profile, :active)] } + it 'redirects to the root url' do + get :index + + expect(response).to redirect_to root_url + end + end + end + + describe '#update' do + let(:profiles) { [create(:profile, deactivation_reason: :password_reset)] } + + it 'redirects user to verify_url' do + put :update + + expect(subject.user_session[:acknowledge_personal_key]).to be_nil + expect(response).to redirect_to verify_url + end + end +end diff --git a/spec/controllers/verify_controller_spec.rb b/spec/controllers/verify_controller_spec.rb index 05119f85df6..ca51bf85787 100644 --- a/spec/controllers/verify_controller_spec.rb +++ b/spec/controllers/verify_controller_spec.rb @@ -34,6 +34,16 @@ expect(response).to redirect_to verify_fail_url end + + it 'redirects to account recovery if user has a password reset profile' do + profile = create(:profile, deactivation_reason: :password_reset) + stub_sign_in(profile.user) + allow(subject).to receive(:user_session).and_return(acknowledge_personal_key: true) + + get :index + + expect(response).to redirect_to manage_reactivate_account_url + end end describe '#activated' do diff --git a/spec/features/users/password_recovery_via_recovery_code_spec.rb b/spec/features/users/password_recovery_via_recovery_code_spec.rb index 17ecdf7660d..b6f33f6adb6 100644 --- a/spec/features/users/password_recovery_via_recovery_code_spec.rb +++ b/spec/features/users/password_recovery_via_recovery_code_spec.rb @@ -16,6 +16,10 @@ click_submit_default enter_correct_otp_code_for_user(user) + expect(current_path).to eq manage_reactivate_account_path + + click_on t('links.account.reactivate.with_key') + expect(current_path).to eq reactivate_account_path reactivate_profile(new_password, personal_key) @@ -33,8 +37,6 @@ click_submit_default enter_correct_otp_code_for_user(user) - expect(current_path).to eq reactivate_account_path - visit manage_personal_key_path new_personal_key = scrape_personal_key diff --git a/spec/features/users/user_profile_spec.rb b/spec/features/users/user_profile_spec.rb index 680a6444f9c..e04ded54ba7 100644 --- a/spec/features/users/user_profile_spec.rb +++ b/spec/features/users/user_profile_spec.rb @@ -74,8 +74,7 @@ reset_password_and_sign_back_in(user, user_password) click_submit_default enter_correct_otp_code_for_user(user) - click_on t('links.cancel') - click_on t('account.index.reactivation.reverify') + click_on t('links.account.reactivate.without_key') click_idv_begin complete_idv_profile_ok(user) click_acknowledge_personal_key