From 1e311247b9da07128f8135377ce621ab35845960 Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Sun, 10 Feb 2019 22:03:57 -0500 Subject: [PATCH 01/10] LG-538 New Document Authentication Design **Why**: So our users can verify their identity on mobile phones with a camera or desktop computers with a scanned image. **How**: Detect whether a user is one a mobile phone or a desktop. Add new flows to accomodate desktop computers, mobile phones, desktop computers to mobile phones (ie user wants to use their camera), and mobile phones to desktop computers (ie user has a scanner). Add image previews on document uploads. Supply different verbiage for taking a picture vs. uploading an image. --- .reek.yml | 2 + app/assets/images/idv/desktop.png | Bin 0 -> 4763 bytes app/assets/images/idv/phone.png | Bin 0 -> 6035 bytes app/decorators/identity_decorator.rb | 4 ++ app/javascript/packs/image-preview.js | 18 ++++++ app/jobs/sms_doc_auth_link_job.rb | 16 ++++++ app/mailers/user_mailer.rb | 6 ++ app/services/flow/base_flow.rb | 5 +- app/services/flow/base_step.rb | 4 +- app/services/flow/flow_state_machine.rb | 4 +- app/services/idv/flows/doc_auth_flow.rb | 11 ++++ .../idv/presenters/doc_auth_presenter.rb | 16 ++++++ app/services/idv/steps/email_sent_step.rb | 7 +++ app/services/idv/steps/link_sent_step.rb | 7 +++ .../idv/steps/mobile_back_image_step.rb | 43 ++++++++++++++ .../idv/steps/mobile_front_image_step.rb | 24 ++++++++ app/services/idv/steps/send_link_step.rb | 29 ++++++++++ app/services/idv/steps/upload_step.rb | 53 +++++++++++++++++ app/services/idv/steps/welcome_step.rb | 7 +++ app/views/idv/doc_auth/back_image.html.slim | 6 +- app/views/idv/doc_auth/email_sent.html.slim | 8 +++ app/views/idv/doc_auth/front_image.html.slim | 17 ++---- app/views/idv/doc_auth/link_sent.html.slim | 8 +++ .../idv/doc_auth/mobile_back_image.html.slim | 27 +++++++++ .../idv/doc_auth/mobile_front_image.html.slim | 25 ++++++++ app/views/idv/doc_auth/send_link.html.slim | 26 +++++++++ app/views/idv/doc_auth/upload.html.slim | 38 ++++++++++++ app/views/idv/doc_auth/welcome.html.slim | 35 ++++++++++++ .../doc_auth_desktop_link_to_sp.html.slim | 1 + config/locales/doc_auth/en.yml | 54 +++++++++++++++--- config/locales/doc_auth/es.yml | 6 -- config/locales/doc_auth/fr.yml | 7 --- config/locales/jobs/en.yml | 3 + config/locales/user_mailer/en.yml | 3 + 34 files changed, 483 insertions(+), 37 deletions(-) create mode 100644 app/assets/images/idv/desktop.png create mode 100644 app/assets/images/idv/phone.png create mode 100644 app/javascript/packs/image-preview.js create mode 100644 app/jobs/sms_doc_auth_link_job.rb create mode 100644 app/services/idv/presenters/doc_auth_presenter.rb create mode 100644 app/services/idv/steps/email_sent_step.rb create mode 100644 app/services/idv/steps/link_sent_step.rb create mode 100644 app/services/idv/steps/mobile_back_image_step.rb create mode 100644 app/services/idv/steps/mobile_front_image_step.rb create mode 100644 app/services/idv/steps/send_link_step.rb create mode 100644 app/services/idv/steps/upload_step.rb create mode 100644 app/services/idv/steps/welcome_step.rb create mode 100644 app/views/idv/doc_auth/email_sent.html.slim create mode 100644 app/views/idv/doc_auth/link_sent.html.slim create mode 100644 app/views/idv/doc_auth/mobile_back_image.html.slim create mode 100644 app/views/idv/doc_auth/mobile_front_image.html.slim create mode 100644 app/views/idv/doc_auth/send_link.html.slim create mode 100644 app/views/idv/doc_auth/upload.html.slim create mode 100644 app/views/idv/doc_auth/welcome.html.slim create mode 100644 app/views/user_mailer/doc_auth_desktop_link_to_sp.html.slim diff --git a/.reek.yml b/.reek.yml index 2d2564850b1..612eab63723 100644 --- a/.reek.yml +++ b/.reek.yml @@ -89,6 +89,7 @@ detectors: - Idv::VendorResult - CloudhsmKeyGenerator - CloudhsmKeySharer + - UserMailer - WebauthnSetupForm - WebauthnVerificationForm TooManyStatements: @@ -166,6 +167,7 @@ detectors: - SessionTimeoutWarningHelper#start - SessionTimeoutWarningHelper#warning - SessionDecorator + - SmsDocAuthLinkJob#perform - UserEncryptedAttributeOverrides#create_fingerprint - LocaleHelper#locale_url_param - IdvSession#timed_out_vendor_error diff --git a/app/assets/images/idv/desktop.png b/app/assets/images/idv/desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..5f84d53d41a33c4cdc19bc7ebcc066d5bf567c4e GIT binary patch literal 4763 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 literal 0 HcmV?d00001 diff --git a/app/assets/images/idv/phone.png b/app/assets/images/idv/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..691a5c3903845ad67a06c1cafc4288f64790f7f4 GIT binary patch literal 6035 zcmds4^;;B7*WRV2krqUxVS%MtmL;T@mW~zalwM!~X;4Z+q*J7%1eQ*hMv*S*4oOK7 zgpcQW-|u~&>-zqKZ?0=*&YW}K=gc|t!^}i!YbuivJ|F}D03>h~1)aND`>y*C;N6Yy z8v9rQ078s|yu3DCUY=Ro!`0T|g$)3p5|x~Sua`7H)3%0DbRMV7McS+%acm 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 literal 0 HcmV?d00001 diff --git a/app/decorators/identity_decorator.rb b/app/decorators/identity_decorator.rb index 15d9544be6a..33fdf0fe4b6 100644 --- a/app/decorators/identity_decorator.rb +++ b/app/decorators/identity_decorator.rb @@ -18,6 +18,10 @@ def return_to_sp_url identity.sp_metadata[:return_to_sp_url] end + def friendly_name + identity.sp_metadata[:friendly_name] + end + def created_at_in_words UtcTimePresenter.new(created_at).to_s end diff --git a/app/javascript/packs/image-preview.js b/app/javascript/packs/image-preview.js new file mode 100644 index 00000000000..a6228db534b --- /dev/null +++ b/app/javascript/packs/image-preview.js @@ -0,0 +1,18 @@ +import $ from 'jquery'; + +function imagePreview() { + $('#doc_auth_image').on('change', function(event) { + var files = event.target.files; + var image = files[0]; + var reader = new FileReader(); + reader.onload = function(file) { + var img = new Image(); + img.src = file.target.result; + // document.getElementById('target').innerHTML = img; + $('#target').html(img); + } + reader.readAsDataURL(image); + }); +} + +document.addEventListener('DOMContentLoaded', imagePreview); diff --git a/app/jobs/sms_doc_auth_link_job.rb b/app/jobs/sms_doc_auth_link_job.rb new file mode 100644 index 00000000000..534b9f2117b --- /dev/null +++ b/app/jobs/sms_doc_auth_link_job.rb @@ -0,0 +1,16 @@ +class SmsDocAuthLinkJob < ApplicationJob + queue_as :sms + include Rails.application.routes.url_helpers + + def perform(phone:, link:, app:) + message = I18n.t( + 'jobs.sms_doc_auth_link_job.message', + sp_link: link, + application: app, + ) + TwilioService::Utils.new.send_sms( + to: phone, + body: message, + ) + end +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index d1d6e0c453a..90ffddce60a 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -61,4 +61,10 @@ def please_reset_password(email_address) def undeliverable_address(email_address) mail(to: email_address.email, subject: t('user_mailer.undeliverable_address.subject')) end + + def doc_auth_desktop_link_to_sp(email_address, application, link) + @link = link + @application = application + mail(to: email_address, subject: 'Verify your identity on a desktop computer') + end end diff --git a/app/services/flow/base_flow.rb b/app/services/flow/base_flow.rb index c74187c0e57..c10da8cf645 100644 --- a/app/services/flow/base_flow.rb +++ b/app/services/flow/base_flow.rb @@ -1,7 +1,7 @@ module Flow class BaseFlow attr_accessor :flow_session - attr_reader :steps, :actions, :current_user, :params + attr_reader :steps, :actions, :current_user, :params, :request def initialize(steps, actions, session, current_user) @current_user = current_user @@ -18,11 +18,12 @@ def next_step step end - def handle(step, params) + def handle(step, request, params) @flow_session[:error_message] = nil handler = steps[step] || actions[step] return failure("Unhandled step #{step}") unless handler @params = params + @request = request wrap_send(handler) end diff --git a/app/services/flow/base_step.rb b/app/services/flow/base_step.rb index 7d835a3f744..3d1c12c57fe 100644 --- a/app/services/flow/base_step.rb +++ b/app/services/flow/base_step.rb @@ -1,5 +1,7 @@ module Flow class BaseStep + include Rails.application.routes.url_helpers + def initialize(context, name) @context = context @form_response = nil @@ -40,6 +42,6 @@ def reset @context.flow_session = {} end - delegate :flow_session, :current_user, :params, :steps, to: :@context + delegate :flow_session, :current_user, :params, :steps, :request, to: :@context end end diff --git a/app/services/flow/flow_state_machine.rb b/app/services/flow/flow_state_machine.rb index 4c2e89eda9e..859cecabd17 100644 --- a/app/services/flow/flow_state_machine.rb +++ b/app/services/flow/flow_state_machine.rb @@ -21,7 +21,7 @@ def show def update step = params[:step] - result = flow.handle(step, params) + result = flow.handle(step, request, params) analytics.track_event(analytics_submitted, result.to_h.merge(step: step)) if @analytics_id render_update(step, result) end @@ -50,6 +50,8 @@ def move_to_next_step end def render_step(step, flow_session) + @params = params + @request = request render template: "#{@name}/#{step}", locals: { flow_session: flow_session } end diff --git a/app/services/idv/flows/doc_auth_flow.rb b/app/services/idv/flows/doc_auth_flow.rb index 0491b3d7368..8bb0209a8d6 100644 --- a/app/services/idv/flows/doc_auth_flow.rb +++ b/app/services/idv/flows/doc_auth_flow.rb @@ -2,8 +2,15 @@ module Idv module Flows class DocAuthFlow < Flow::BaseFlow STEPS = { + welcome: Idv::Steps::WelcomeStep, + upload: Idv::Steps::UploadStep, + send_link: Idv::Steps::SendLinkStep, + link_sent: Idv::Steps::LinkSentStep, + email_sent: Idv::Steps::EmailSentStep, front_image: Idv::Steps::FrontImageStep, back_image: Idv::Steps::BackImageStep, + mobile_front_image: Idv::Steps::MobileFrontImageStep, + mobile_back_image: Idv::Steps::MobileBackImageStep, ssn: Idv::Steps::SsnStep, doc_failed: Idv::Steps::DocFailedStep, doc_success: Idv::Steps::DocSuccessStep, @@ -13,6 +20,10 @@ class DocAuthFlow < Flow::BaseFlow reset: Idv::Actions::ResetAction, }.freeze + PRESENTERS = { + front_image: Idv::Presenters::DocAuthPresenter, + }.freeze + attr_reader :idv_session # this is needed to support (and satisfy) the current LOA3 flow def initialize(session, current_user, name) diff --git a/app/services/idv/presenters/doc_auth_presenter.rb b/app/services/idv/presenters/doc_auth_presenter.rb new file mode 100644 index 00000000000..0076e8d6b2d --- /dev/null +++ b/app/services/idv/presenters/doc_auth_presenter.rb @@ -0,0 +1,16 @@ +module Idv + module Presenters + class DocAuthPresenter + def initialize(session, request, params) + @session = session + @request = request + @params = params + end + + def mobile? + client = DeviceDetector.new(@request.user_agent) + client.device_type != 'desktop' + end + end + end +end diff --git a/app/services/idv/steps/email_sent_step.rb b/app/services/idv/steps/email_sent_step.rb new file mode 100644 index 00000000000..cb93d721ff7 --- /dev/null +++ b/app/services/idv/steps/email_sent_step.rb @@ -0,0 +1,7 @@ +module Idv + module Steps + class EmailSentStep < DocAuthBaseStep + def call; end + end + end +end diff --git a/app/services/idv/steps/link_sent_step.rb b/app/services/idv/steps/link_sent_step.rb new file mode 100644 index 00000000000..6b965202e40 --- /dev/null +++ b/app/services/idv/steps/link_sent_step.rb @@ -0,0 +1,7 @@ +module Idv + module Steps + class LinkSentStep < DocAuthBaseStep + def call; end + end + end +end diff --git a/app/services/idv/steps/mobile_back_image_step.rb b/app/services/idv/steps/mobile_back_image_step.rb new file mode 100644 index 00000000000..76db9be85d5 --- /dev/null +++ b/app/services/idv/steps/mobile_back_image_step.rb @@ -0,0 +1,43 @@ +module Idv + module Steps + class MobileBackImageStep < DocAuthBaseStep + def call + good, data = assure_id.post_back_image(image.read) + return failure(data) unless good + + failure_data, data = verify_back_image + return failure_data if failure_data + + extract_pii_from_doc(data) + end + + private + + def form_submit + Idv::ImageUploadForm.new(current_user).submit(permit(:image)) + end + + def extract_pii_from_doc(data) + pii_from_doc = Idv::Utils::PiiFromDoc.new(data).call( + current_user.phone_configurations.first.phone, + ) + flow_session[:pii_from_doc] = pii_from_doc + end + + def verify_back_image + back_image_verified, data = assure_id.results + return failure(data) unless back_image_verified + + return [nil, data] if data['Result'] == 1 + + failure_alerts(data) + end + + def failure_alerts(data) + failure(data['Alerts']. + reject { |res| res['Result'] == 2 }. + map { |act| act['Actions'] }) + end + end + end +end diff --git a/app/services/idv/steps/mobile_front_image_step.rb b/app/services/idv/steps/mobile_front_image_step.rb new file mode 100644 index 00000000000..ab73dc200fb --- /dev/null +++ b/app/services/idv/steps/mobile_front_image_step.rb @@ -0,0 +1,24 @@ +module Idv + module Steps + class MobileFrontImageStep < DocAuthBaseStep + def call + success, instance_id_or_message = assure_id.create_document + return failure(instance_id_or_message) unless success + + flow_session[:instance_id] = instance_id_or_message + upload_front_image + end + + private + + def form_submit + Idv::ImageUploadForm.new(current_user).submit(permit(:image)) + end + + def upload_front_image + success, message = assure_id.post_front_image(image.read) + return failure(message) unless success + end + end + end +end diff --git a/app/services/idv/steps/send_link_step.rb b/app/services/idv/steps/send_link_step.rb new file mode 100644 index 00000000000..78f5ad2b937 --- /dev/null +++ b/app/services/idv/steps/send_link_step.rb @@ -0,0 +1,29 @@ +module Idv + module Steps + class SendLinkStep < DocAuthBaseStep + def call + SmsDocAuthLinkJob.perform_now( + phone: permit(:phone), + link: link, + app: app, + ) + end + + private + + def form_submit + Idv::PhoneForm.new(previous_params: {}, user: current_user).submit(permit(:phone)) + end + + def link + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. + return_to_sp_url || root_url + end + + def app + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. + friendly_name || 'login.gov' + end + end + end +end diff --git a/app/services/idv/steps/upload_step.rb b/app/services/idv/steps/upload_step.rb new file mode 100644 index 00000000000..0a6c99d7eb6 --- /dev/null +++ b/app/services/idv/steps/upload_step.rb @@ -0,0 +1,53 @@ +module Idv + module Steps + class UploadStep < DocAuthBaseStep + def call + have_mobile = mobile? + if params[:type] == 'desktop' + have_mobile ? mobile_to_desktop : desktop + else + have_mobile ? mobile : mark_step_complete(:email_sent) + end + end + + private + + def mobile? + client = DeviceDetector.new(request.user_agent) + client.device_type != 'desktop' + end + + def link + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. + return_to_sp_url || root_url + end + + def application + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. + friendly_name || 'login.gov' + end + + def mobile_to_desktop + mark_step_complete(:send_link) + mark_step_complete(:link_sent) + UserMailer.doc_auth_desktop_link_to_sp(current_user.email, application, link).deliver_later + end + + def desktop + mark_step_complete(:send_link) + mark_step_complete(:link_sent) + mark_step_complete(:email_sent) + mark_step_complete(:mobile_front_image) + mark_step_complete(:mobile_back_image) + end + + def mobile + mark_step_complete(:send_link) + mark_step_complete(:link_sent) + mark_step_complete(:email_sent) + mark_step_complete(:front_image) + mark_step_complete(:back_image) + end + end + end +end diff --git a/app/services/idv/steps/welcome_step.rb b/app/services/idv/steps/welcome_step.rb new file mode 100644 index 00000000000..7aa20855975 --- /dev/null +++ b/app/services/idv/steps/welcome_step.rb @@ -0,0 +1,7 @@ +module Idv + module Steps + class WelcomeStep < DocAuthBaseStep + def call; end + end + end +end diff --git a/app/views/idv/doc_auth/back_image.html.slim b/app/views/idv/doc_auth/back_image.html.slim index 94c8b061798..5248cfb3a6f 100644 --- a/app/views/idv/doc_auth/back_image.html.slim +++ b/app/views/idv/doc_auth/back_image.html.slim @@ -1,7 +1,8 @@ -title t('doc_auth.titles.doc_auth') -h1.h3 = t('doc_auth.headings.upload_back') +h1.h3.mb0 = t('doc_auth.headings.upload_back') +h5.mt0 = t('doc_auth.info.upload_image') = simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :back_image), method: 'PUT', html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do |f| .clearfix.mxn1 @@ -10,8 +11,11 @@ h1.h3 = t('doc_auth.headings.upload_back') p = flow_session[:error_message] + div id= 'target' + br .mt4 button type='submit' class='btn btn-primary btn-wide sm-col-6 col-12' = t('forms.buttons.continue') = render 'start_over_or_cancel' +== javascript_pack_tag 'image-preview' diff --git a/app/views/idv/doc_auth/email_sent.html.slim b/app/views/idv/doc_auth/email_sent.html.slim new file mode 100644 index 00000000000..e31895c03f6 --- /dev/null +++ b/app/views/idv/doc_auth/email_sent.html.slim @@ -0,0 +1,8 @@ +- title t('doc_auth.titles.doc_auth') + += image_tag(asset_url('state-id-confirm@3x.png'), + alt: t('idv.titles.session.success'), width: 210) + +h1.h3.mb2.mt3.my0 = t('doc_auth.instructions.email_sent', email: current_user.email) + += render 'start_over_or_cancel' diff --git a/app/views/idv/doc_auth/front_image.html.slim b/app/views/idv/doc_auth/front_image.html.slim index 1580559d449..5dc8e408eb9 100644 --- a/app/views/idv/doc_auth/front_image.html.slim +++ b/app/views/idv/doc_auth/front_image.html.slim @@ -1,25 +1,20 @@ - title t('doc_auth.titles.doc_auth') -= image_tag(asset_url('state-id-none@3x.png'), - alt: t('idv.titles.jurisdiction'), width: 210) +h1.h3.mb0 = t('doc_auth.headings.upload_front') -h1.h3.mb0 = t('doc_auth.headings.intro') -p = flow_session[:error_message] - -ul - li = t('doc_auth.forms.option_1') - li = t('doc_auth.forms.option_2') - li = link_to t('idv.messages.jurisdiction.no_id'), idv_jurisdiction_failure_path(:no_id) -br -h5.mt0 = t('doc_auth.headings.upload_front') +h5.mt0 = t('doc_auth.info.upload_image') = simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :front_image), method: 'PUT', html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do |f| .clearfix.mxn1 .sm-col.sm-col-8.px1 = f.input :image, label: false, as: 'file', required: true + p.red.bold = flow_session[:error_message] + div id= 'target' + br .mt0 button type='submit' class='btn btn-primary btn-wide sm-col-6 col-6' = t('forms.buttons.continue') br = render 'start_over_or_cancel' +== javascript_pack_tag 'image-preview' diff --git a/app/views/idv/doc_auth/link_sent.html.slim b/app/views/idv/doc_auth/link_sent.html.slim new file mode 100644 index 00000000000..6663c4fc831 --- /dev/null +++ b/app/views/idv/doc_auth/link_sent.html.slim @@ -0,0 +1,8 @@ +- title t('doc_auth.titles.doc_auth') + += image_tag(asset_url('state-id-confirm@3x.png'), + alt: t('idv.titles.session.success'), width: 210) + +h1.h3.mb2.mt3.my0 = t('doc_auth.info.link_sent') + += render 'start_over_or_cancel' diff --git a/app/views/idv/doc_auth/mobile_back_image.html.slim b/app/views/idv/doc_auth/mobile_back_image.html.slim new file mode 100644 index 00000000000..47b6a607f61 --- /dev/null +++ b/app/views/idv/doc_auth/mobile_back_image.html.slim @@ -0,0 +1,27 @@ +-title t('doc_auth.titles.doc_auth') + +h1.h3.mb0 = t('doc_auth.headings.take_pic_back') + +h5.mt0 = t('doc_auth.instructions.take_pic') +ul + li = t('doc_auth.instructions.take_pic1') + li = t('doc_auth.instructions.take_pic2') + li = t('doc_auth.instructions.take_pic3') + li = t('doc_auth.instructions.take_pic4') + += simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :mobile_back_image), method: 'PUT', + html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do |f| + .clearfix.mxn1 + .sm-col.sm-col-9.px1 + = f.input :image, label: false, as: 'file', required: true + + p = flow_session[:error_message] + + div id= 'target' + br + .mt4 + button type='submit' class='btn btn-primary btn-wide sm-col-6 col-12' + = t('forms.buttons.continue') + += render 'start_over_or_cancel' +== javascript_pack_tag 'image-preview' diff --git a/app/views/idv/doc_auth/mobile_front_image.html.slim b/app/views/idv/doc_auth/mobile_front_image.html.slim new file mode 100644 index 00000000000..305e5aa25f0 --- /dev/null +++ b/app/views/idv/doc_auth/mobile_front_image.html.slim @@ -0,0 +1,25 @@ +- title t('doc_auth.titles.doc_auth') + +h1.h3.mb0 = t('doc_auth.headings.take_pic_back') + +h5.mt0 = t('doc_auth.instructions.take_pic') +ul + li = t('doc_auth.instructions.take_pic1') + li = t('doc_auth.instructions.take_pic2') + li = t('doc_auth.instructions.take_pic3') + li = t('doc_auth.instructions.take_pic4') + += simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :mobile_front_image), method: 'PUT', + html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do |f| + .clearfix.mxn1 + .sm-col.sm-col-8.px1 + = f.input :image, label: false, as: 'file', required: true + div id= 'target' + br + .mt0 + button type='submit' class='btn btn-primary btn-wide sm-col-6 col-6' + = t('forms.buttons.continue') +br + += render 'start_over_or_cancel' +== javascript_pack_tag 'image-preview' diff --git a/app/views/idv/doc_auth/send_link.html.slim b/app/views/idv/doc_auth/send_link.html.slim new file mode 100644 index 00000000000..004b79b111c --- /dev/null +++ b/app/views/idv/doc_auth/send_link.html.slim @@ -0,0 +1,26 @@ +- title t('doc_auth.titles.doc_auth') + +h1.h3 = t('doc_auth.headings.take_picture') + +p.mt-tiny.mb3 = t('doc_auth.info.take_picture') + +p.mt-tiny.mb3.bold = t('doc_auth.info.camera_required') + +p.mt-tiny.mb3 = t('doc_auth.instructions.send_sms') + += simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :send_link), method: 'PUT', + html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do |f| + .clearfix.mxn1 + .sm-col.sm-col-8.px1 + / using :tel for mobile numeric keypad + = f.label :phone, label: t('idv.form.phone'), class: 'bold' + = f.input :phone, required: true, input_html: { class: 'us-phone sm-col-8' }, label: false, + wrapper_html: { class: 'mr2' } + + p.green.bold = flow_session[:error_message] + + .mt0 + button type='submit' class='btn btn-primary btn-wide sm-col-6 col-12' + = t('forms.buttons.continue') + += render 'start_over_or_cancel' diff --git a/app/views/idv/doc_auth/upload.html.slim b/app/views/idv/doc_auth/upload.html.slim new file mode 100644 index 00000000000..fd151ceba0e --- /dev/null +++ b/app/views/idv/doc_auth/upload.html.slim @@ -0,0 +1,38 @@ +- title t('doc_auth.titles.doc_auth') + +h1.h3.mb0 = t('doc_auth.headings.upload') += t('doc_auth.info.upload') +br +br += link_to t('idv.messages.jurisdiction.no_id'), idv_jurisdiction_failure_path(:no_id) +br +br +hr +br + .clearfix.mxn1 + .sm-col.sm-col-2 = image_tag asset_url('idv/desktop.png'), width: 100 + .sm-col.sm-col-1   + .sm-col.sm-col-9 + .bold.h1 = t('doc_auth.headings.upload_from_computer') + = t('doc_auth.info.upload_from_computer') + = simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :upload, type: :desktop), + method: 'PUT', html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do + button type='submit' class='btn btn-primary' + = t('doc_auth.buttons.use_computer') + br + hr + .clearfix.mxn1 + .sm-col.sm-col-2 = image_tag asset_url('idv/phone.png'), width: 100 + .sm-col.sm-col-1   + .sm-col.sm-col-9 + .bold.h1 = t('doc_auth.headings.upload_from_phone') + = t('doc_auth.info.upload_from_phone') + br + = simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :upload, type: :mobile), + method: 'PUT', html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do + button type='submit' class='btn btn-primary' + = t('doc_auth.buttons.use_phone') +br + += render 'start_over_or_cancel' +== javascript_pack_tag 'image-preview' diff --git a/app/views/idv/doc_auth/welcome.html.slim b/app/views/idv/doc_auth/welcome.html.slim new file mode 100644 index 00000000000..6925fb3137b --- /dev/null +++ b/app/views/idv/doc_auth/welcome.html.slim @@ -0,0 +1,35 @@ +h1.h3.my0 = t('doc_auth.headings.welcome') +p.mt-tiny.mb3 = t('doc_auth.info.welcome') +h1.h3.my0 = t('doc_auth.instructions.welcome') +ul.list-reset + li.py2 + .mr1.inline-block.circle.circle-number.bg-blue.white + | 1 + .h1.inline-block.bold = t('doc_auth.instructions.bullet1') + br + .ml3 = t('doc_auth.instructions.text1') + li.py2 + .mr1.inline-block.circle.circle-number.bg-blue.white + | 2 + .h1.inline-block.bold = t('doc_auth.instructions.bullet2') + .ml3 = t('doc_auth.instructions.text2') + li.py2 + .mr1.inline-block.circle.circle-number.bg-blue.white + | 3 + .h1.inline-block.bold = t('doc_auth.instructions.bullet3') + .ml3 = t('doc_auth.instructions.text3') + li.py2 + .mr1.inline-block.circle.circle-number.bg-blue.white + | 3 + .h1.inline-block.bold = t('doc_auth.instructions.bullet4') + .ml3 = t('doc_auth.instructions.text4') += simple_form_for(:doc_auth, url: idv_doc_auth_step_path(step: :welcome), method: 'PUT', + html: { autocomplete: 'off', role: 'form', class: 'mt2' }) do + br + .mt0 + button type='submit' class='btn btn-primary btn-wide sm-col-6 col-6' + = t('doc_auth.buttons.get_started') +br += render 'shared/cancel_or_back_to_options' + +== javascript_pack_tag 'clipboard' diff --git a/app/views/user_mailer/doc_auth_desktop_link_to_sp.html.slim b/app/views/user_mailer/doc_auth_desktop_link_to_sp.html.slim new file mode 100644 index 00000000000..24bce18db1e --- /dev/null +++ b/app/views/user_mailer/doc_auth_desktop_link_to_sp.html.slim @@ -0,0 +1 @@ +== I18n.t('user_mailer.doc_auth_link.message', sp_link: link_to(@application, @link)) diff --git a/config/locales/doc_auth/en.yml b/config/locales/doc_auth/en.yml index c072cb8331c..15ae728c1d4 100644 --- a/config/locales/doc_auth/en.yml +++ b/config/locales/doc_auth/en.yml @@ -2,7 +2,10 @@ en: doc_auth: buttons: + get_started: Get started start_over: Start over + use_computer: Use your computer + use_phone: Use your phone errors: state_id_fail: Sorry. Information from your uploaded state-issued ID does not match information for your social security number. @@ -12,17 +15,52 @@ en: entered_info: 'Information you entered:' first_name: First Name last_name: Last Name - option_1: 'Desktop computer users: You need a scanned copy of your id. If you - do not have one please sign in from a mobile phone.' - option_2: 'Mobile phone users: You can use your camera or photos from your camera - roll.' ssn: Social Security Number state_id_info: 'Information from your uploaded state-issued ID:' headings: - intro: To verify your identity, you'll need your social security number and - state-issued ID. ssn: Please enter your social security number. - upload_back: Please upload a photo of the back of your state-issued ID. - upload_front: Please upload a photo of the front of your state-issued ID. + take_pic_back: Take a picture of the back of your ID + take_picture: Take a picture with a phone + upload: How would you like to upload your state issued ID? + upload_back: Upload an image of the back of your state issued ID + upload_from_computer: Upload from your computer + upload_from_phone: Take a picture with a phone to upload your ID + upload_front: Upload an image of the front of your state issued ID + welcome: We need to verify your identity + info: + camera_required: Your mobile phone must have a camera and a web browser + link_sent: Link successfully sent. Please check your phone and follow instructions + to verify your identity. + take_picture: Use the camera on your mobile phone and upload images of your + ID. We only use the images to verify your identity. + upload: We'll collect information about you by reading from your state-issued + ID. We do not store images you upload. We only verify your identity. + upload_from_computer: Upload images of your ID you have on your computer or + use a scanner to capture images of your ID + upload_from_phone: Upload pictures directly from your phone camera + upload_image: We only use your ID to verify your identity, and we will not save + any images. We accept PDF, PNG, and JPG formats. + welcome: We verify your identity to make sure you are you--not someone pretending + to be you. Verifying your identity also allows you to access services that + handle Personal Identifiable Information. + instructions: + bullet1: Upload your ID + bullet2: Confirm your address + bullet3: Secure your account + bullet4: Account recovery + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to complete the proofing process + send_sms: We'll send a text message to your device with a link. Follow that + link to your browser to take pictures of the front and back of your ID. + take_pic: 'For best results:' + take_pic1: Use a dark background + take_pic2: Take the photo on a flat surface + take_pic3: Do not use the flash on your camera + take_pic4: Use the landscape orientation + text1: along with your Social Security Number + text2: using a phone number or mailing address + text3: by re-entering your login.gov password + text4: make sure you always have access + welcome: 'What you''ll need to do:' titles: doc_auth: Document Authentication diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml index 43a89e8add5..69e97c1383a 100644 --- a/config/locales/doc_auth/es.yml +++ b/config/locales/doc_auth/es.yml @@ -13,15 +13,9 @@ es: entered_info: 'Información que ingresó:' first_name: Nombre de pila last_name: Apellido - option_1: 'Usuarios de computadoras de escritorio: necesita una copia escaneada - de su identificación. Si no tiene uno, inicie sesión desde un teléfono móvil.' - option_2: 'Usuarios de teléfonos móviles: puede usar su cámara o fotos de su - rollo de cámara.' ssn: Número de seguridad social state_id_info: 'Información de su ID emitida por el estado:' headings: - intro: Para verificar su identidad, necesitará su número de seguro social y - una identificación emitida por el estado. ssn: Por favor ingrese su número de seguro social. upload_back: Cargue una foto del dorso de su identificación emitida por el estado. upload_front: Cargue una foto del frente de su identificación emitida por el diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml index d084c3510b0..aba4389f811 100644 --- a/config/locales/doc_auth/fr.yml +++ b/config/locales/doc_auth/fr.yml @@ -14,16 +14,9 @@ fr: entered_info: 'Informations que vous avez entrées:' first_name: Prénom last_name: Nom de famille - option_1: 'Utilisateurs d''ordinateur de bureau: Vous avez besoin d''une copie - numérisée de votre identifiant. Si vous n''en avez pas, connectez-vous à partir - d''un téléphone portable.' - option_2: 'Utilisateurs de téléphones mobiles: Vous pouvez utiliser votre appareil - photo ou des photos à partir de votre pellicule.' ssn: Numéro de sécurité sociale state_id_info: 'Information from your uploaded state-issued ID:' headings: - intro: Pour vérifier votre identité, vous aurez besoin de votre numéro de sécurité - sociale et de votre identifiant délivré par l'État. ssn: S'il vous plaît entrez votre numéro de sécurité sociale. upload_back: S'il vous plaît télécharger une photo du dos de votre ID émis par l'état. diff --git a/config/locales/jobs/en.yml b/config/locales/jobs/en.yml index 7dcf5fc3266..13abf737e57 100644 --- a/config/locales/jobs/en.yml +++ b/config/locales/jobs/en.yml @@ -7,6 +7,9 @@ en: message: 'You''ve requested to delete your login.gov account. Your request will be processed in 24 hours. If you don’t want to delete your account, please cancel: %{cancel_link}' + sms_doc_auth_link_job: + message: 'You''ve requested to verify your identity on a mobile phone. Please + sign in to %{application}: %{sp_link}' sms_otp_sender_job: login_message: "%{code} is your %{app} security code. Use this to continue signing in to your account. This code will expire in %{expiration} minutes." diff --git a/config/locales/user_mailer/en.yml b/config/locales/user_mailer/en.yml index 8e67232f85a..28c008c9977 100644 --- a/config/locales/user_mailer/en.yml +++ b/config/locales/user_mailer/en.yml @@ -35,6 +35,9 @@ en: to delete your account, %{cancel_account_reset}. subject: Delete your account contact_link_text: contact us + doc_auth_link: + message: You've requested to verify your identity on a desktop computer. Please + sign in to %{sp_link} email_changed: help: If you did not want to change your email address, please visit the %{app} %{help_link} or %{contact_link}. From e070986b75aa03d1c2f892c9a373ffd54101f1fb Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Sun, 10 Feb 2019 22:08:49 -0500 Subject: [PATCH 02/10] Lint on js --- app/javascript/packs/image-preview.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/javascript/packs/image-preview.js b/app/javascript/packs/image-preview.js index a6228db534b..705c37b0c10 100644 --- a/app/javascript/packs/image-preview.js +++ b/app/javascript/packs/image-preview.js @@ -2,15 +2,14 @@ import $ from 'jquery'; function imagePreview() { $('#doc_auth_image').on('change', function(event) { - var files = event.target.files; - var image = files[0]; - var reader = new FileReader(); + const files = event.target.files; + const image = files[0]; + const reader = new FileReader(); reader.onload = function(file) { - var img = new Image(); + const img = new Image(); img.src = file.target.result; - // document.getElementById('target').innerHTML = img; $('#target').html(img); - } + }; reader.readAsDataURL(image); }); } From 36f5151a9be73aacabee95538a16c5777d8eec6e Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Sun, 10 Feb 2019 22:39:52 -0500 Subject: [PATCH 03/10] Fix specs --- spec/features/idv/actions/reset_action_spec.rb | 6 +++--- spec/support/features/doc_auth_helper.rb | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/spec/features/idv/actions/reset_action_spec.rb b/spec/features/idv/actions/reset_action_spec.rb index d46d7a24899..7f8e7290644 100644 --- a/spec/features/idv/actions/reset_action_spec.rb +++ b/spec/features/idv/actions/reset_action_spec.rb @@ -6,14 +6,14 @@ before do enable_doc_auth - complete_doc_auth_steps_before_back_image_step + complete_doc_auth_steps_before_upload_step end it 'resets doc auth to the first step' do - expect(page).to have_current_path(idv_doc_auth_back_image_step) + expect(page).to have_current_path(idv_doc_auth_upload_step) click_on t('doc_auth.buttons.start_over') - expect(page).to have_current_path(idv_doc_auth_front_image_step) + expect(page).to have_current_path(idv_doc_auth_welcome_step) end end diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index 384e3fdcbed..00a7cbceac3 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -49,6 +49,14 @@ def fill_out_ssn_form_fail fill_in 'doc_auth_ssn', with: '' end + def idv_doc_auth_welcome_step + idv_doc_auth_step_path(step: :welcome) + end + + def idv_doc_auth_upload_step + idv_doc_auth_step_path(step: :upload) + end + def idv_doc_auth_ssn_step idv_doc_auth_step_path(step: :ssn) end @@ -73,9 +81,15 @@ def idv_doc_auth_self_image_step idv_doc_auth_step_path(step: :self_image) end - def complete_doc_auth_steps_before_front_image_step(user = user_with_2fa) + def complete_doc_auth_steps_before_upload_step(user = user_with_2fa) sign_in_and_2fa_user(user) - visit idv_doc_auth_front_image_step unless current_path == idv_doc_auth_front_image_step + visit idv_doc_auth_welcome_step unless current_path == idv_doc_auth_welcome_step + click_on t('doc_auth.buttons.get_started') + end + + def complete_doc_auth_steps_before_front_image_step(user = user_with_2fa) + complete_doc_auth_steps_before_upload_step(user) + click_on t('doc_auth.buttons.use_computer') end def complete_doc_auth_steps_before_ssn_step(user = user_with_2fa) From 643f371b4553bb85866729185d8596bfc5e3af80 Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Sun, 10 Feb 2019 23:03:16 -0500 Subject: [PATCH 04/10] Fix more specs --- spec/controllers/idv/doc_auth_controller_spec.rb | 6 +++--- spec/services/idv/flows/doc_auth_flow_spec.rb | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/controllers/idv/doc_auth_controller_spec.rb b/spec/controllers/idv/doc_auth_controller_spec.rb index 96c99966539..3a8dda9523b 100644 --- a/spec/controllers/idv/doc_auth_controller_spec.rb +++ b/spec/controllers/idv/doc_auth_controller_spec.rb @@ -23,7 +23,7 @@ it 'redirects to the first step' do get :index - expect(response).to redirect_to idv_doc_auth_step_url(step: :front_image) + expect(response).to redirect_to idv_doc_auth_step_url(step: :welcome) end end @@ -63,9 +63,9 @@ end it 'tracks analytics' do - result = { step: 'front_image' } + result = { step: 'welcome' } - get :show, params: { step: 'front_image' } + get :show, params: { step: 'welcome' } expect(@analytics).to have_received(:track_event).with( Analytics::DOC_AUTH + ' visited', result diff --git a/spec/services/idv/flows/doc_auth_flow_spec.rb b/spec/services/idv/flows/doc_auth_flow_spec.rb index 629070b7d91..dbd0fc0e15a 100644 --- a/spec/services/idv/flows/doc_auth_flow_spec.rb +++ b/spec/services/idv/flows/doc_auth_flow_spec.rb @@ -8,19 +8,19 @@ let(:name) { :doc_auth } describe '#next_step' do - it 'returns front_image as the first step' do + it 'returns welcome as the first step' do subject = Idv::Flows::DocAuthFlow.new(new_session, user, name) result = subject.next_step - expect(result).to eq('front_image') + expect(result).to eq('welcome') end - it 'returns back image after the front image step' do - expect_next_step(:front_image, :back_image) + it 'returns upload after the welcome step' do + expect_next_step(:welcome, :upload) end - it 'returns ssn after the back image step' do - expect_next_step(:back_image, :ssn) + it 'returns back_image after the front image step' do + expect_next_step(:front_image, :back_image) end end @@ -30,7 +30,7 @@ params = ActionController::Parameters.new(doc_auth: { ssn: '111111111' }) expect_any_instance_of(Idv::Steps::SsnStep).to receive(:call).exactly(:once) - result = subject.handle(:ssn, params) + result = subject.handle(:ssn, {}, params) expect(result.class).to eq(FormResponse) expect(result.success?).to eq(true) end From 1cd66109b60314d8b18a36eea43edd6239d8e99e Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Sun, 10 Feb 2019 23:22:59 -0500 Subject: [PATCH 05/10] Locale files --- config/locales/doc_auth/es.yml | 44 +++++++++++++++++++++++++++++++ config/locales/doc_auth/fr.yml | 44 +++++++++++++++++++++++++++++++ config/locales/jobs/es.yml | 3 +++ config/locales/jobs/fr.yml | 3 +++ config/locales/user_mailer/es.yml | 3 +++ config/locales/user_mailer/fr.yml | 3 +++ 6 files changed, 100 insertions(+) diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml index 69e97c1383a..6312ac5a72c 100644 --- a/config/locales/doc_auth/es.yml +++ b/config/locales/doc_auth/es.yml @@ -2,7 +2,10 @@ es: doc_auth: buttons: + get_started: Get started start_over: Comenzar de nuevo + use_computer: Use your computer + use_phone: Use your phone errors: state_id_fail: Lo siento. La información de su ID emitida por el estado no coincide con la información de su número de seguro social. @@ -17,8 +20,49 @@ es: state_id_info: 'Información de su ID emitida por el estado:' headings: ssn: Por favor ingrese su número de seguro social. + take_pic_back: Take a picture of the back of your ID + take_picture: Take a picture with a phone + upload: How would you like to upload your state issued ID? upload_back: Cargue una foto del dorso de su identificación emitida por el estado. + upload_from_computer: Upload from your computer + upload_from_phone: Take a picture with a phone to upload your ID upload_front: Cargue una foto del frente de su identificación emitida por el estado. + welcome: We need to verify your identity + info: + camera_required: Your mobile phone must have a camera and a web browser + link_sent: Link successfully sent. Please check your phone and follow instructions + to verify your identity. + take_picture: Use the camera on your mobile phone and upload images of your + ID. We only use the images to verify your identity. + upload: We'll collect information about you by reading from your state-issued + ID. We do not store images you upload. We only verify your identity. + upload_from_computer: Upload images of your ID you have on your computer or + use a scanner to capture images of your ID + upload_from_phone: Upload pictures directly from your phone camera + upload_image: We only use your ID to verify your identity, and we will not save + any images. We accept PDF, PNG, and JPG formats. + welcome: We verify your identity to make sure you are you--not someone pretending + to be you. Verifying your identity also allows you to access services that + handle Personal Identifiable Information. + instructions: + bullet1: Upload your ID + bullet2: Confirm your address + bullet3: Secure your account + bullet4: Account recovery + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to complete the proofing process + send_sms: We'll send a text message to your device with a link. Follow that + link to your browser to take pictures of the front and back of your ID. + take_pic: 'For best results:' + take_pic1: Use a dark background + take_pic2: Take the photo on a flat surface + take_pic3: Do not use the flash on your camera + take_pic4: Use the landscape orientation + text1: along with your Social Security Number + text2: using a phone number or mailing address + text3: by re-entering your login.gov password + text4: make sure you always have access + welcome: 'What you''ll need to do:' titles: doc_auth: Autenticación de documentos diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml index aba4389f811..2a75102364d 100644 --- a/config/locales/doc_auth/fr.yml +++ b/config/locales/doc_auth/fr.yml @@ -2,7 +2,10 @@ fr: doc_auth: buttons: + get_started: Get started start_over: Recommencer + use_computer: Use your computer + use_phone: Use your phone errors: state_id_fail: Pardon. Les informations de votre identifiant émis par l'état téléchargé ne correspondent pas aux informations de votre numéro de sécurité @@ -18,9 +21,50 @@ fr: state_id_info: 'Information from your uploaded state-issued ID:' headings: ssn: S'il vous plaît entrez votre numéro de sécurité sociale. + take_pic_back: Take a picture of the back of your ID + take_picture: Take a picture with a phone + upload: How would you like to upload your state issued ID? upload_back: S'il vous plaît télécharger une photo du dos de votre ID émis par l'état. + upload_from_computer: Upload from your computer + upload_from_phone: Take a picture with a phone to upload your ID upload_front: Veuillez télécharger une photo du recto de votre identifiant émis par l'État. + welcome: We need to verify your identity + info: + camera_required: Your mobile phone must have a camera and a web browser + link_sent: Link successfully sent. Please check your phone and follow instructions + to verify your identity. + take_picture: Use the camera on your mobile phone and upload images of your + ID. We only use the images to verify your identity. + upload: We'll collect information about you by reading from your state-issued + ID. We do not store images you upload. We only verify your identity. + upload_from_computer: Upload images of your ID you have on your computer or + use a scanner to capture images of your ID + upload_from_phone: Upload pictures directly from your phone camera + upload_image: We only use your ID to verify your identity, and we will not save + any images. We accept PDF, PNG, and JPG formats. + welcome: We verify your identity to make sure you are you--not someone pretending + to be you. Verifying your identity also allows you to access services that + handle Personal Identifiable Information. + instructions: + bullet1: Upload your ID + bullet2: Confirm your address + bullet3: Secure your account + bullet4: Account recovery + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to complete the proofing process + send_sms: We'll send a text message to your device with a link. Follow that + link to your browser to take pictures of the front and back of your ID. + take_pic: 'For best results:' + take_pic1: Use a dark background + take_pic2: Take the photo on a flat surface + take_pic3: Do not use the flash on your camera + take_pic4: Use the landscape orientation + text1: along with your Social Security Number + text2: using a phone number or mailing address + text3: by re-entering your login.gov password + text4: make sure you always have access + welcome: 'What you''ll need to do:' titles: doc_auth: Authentification de document diff --git a/config/locales/jobs/es.yml b/config/locales/jobs/es.yml index 9ccc896b97e..20c51cc6c95 100644 --- a/config/locales/jobs/es.yml +++ b/config/locales/jobs/es.yml @@ -7,6 +7,9 @@ es: message: 'Has solicitado eliminar tu cuenta de login.gov. Su solicitud será ser procesado en 24 horas. Si no desea eliminar su cuenta, por favor cancelar: %{cancel_link}' + sms_doc_auth_link_job: + message: 'You''ve requested to verify your identity on a mobile phone. Please + sign in to %{application}: %{sp_link}' sms_otp_sender_job: login_message: "%{code} es tu código de seguridad de %{app}. Use esto para continuar ingresando a su cuenta. Este código caducará en %{expiration} minutos." diff --git a/config/locales/jobs/fr.yml b/config/locales/jobs/fr.yml index 6f7f10fc3c7..26a9856a613 100644 --- a/config/locales/jobs/fr.yml +++ b/config/locales/jobs/fr.yml @@ -7,6 +7,9 @@ fr: message: 'Vous avez demandé à supprimer votre compte login.gov. Votre demande sera être traité en 24 heures. Si vous ne souhaitez pas supprimer votre compte, veuillez cancel: %{cancel_link}' + sms_doc_auth_link_job: + message: 'You''ve requested to verify your identity on a mobile phone. Please + sign in to %{application}: %{sp_link}' sms_otp_sender_job: login_message: "%{code} est votre code de sécurité %{app}. Utilisez-le pour continuer à vous connecter à votre compte. Ce code expirera dans %{expiration} diff --git a/config/locales/user_mailer/es.yml b/config/locales/user_mailer/es.yml index adbb714d4f2..866ab9805fc 100644 --- a/config/locales/user_mailer/es.yml +++ b/config/locales/user_mailer/es.yml @@ -36,6 +36,9 @@ es: su cuenta, %{cancel_account_reset}. subject: Eliminar su cuenta contact_link_text: Contáctenos + doc_auth_link: + message: You've requested to verify your identity on a desktop computer. Please + sign in to %{sp_link} email_changed: help: Si no desea cambiar su email, visite el %{app} %{help_link} o el %{contact_link}. intro: El email de su cuenta de %{app} ha sido cambiado. diff --git a/config/locales/user_mailer/fr.yml b/config/locales/user_mailer/fr.yml index e96cdeaffe6..429d09aed82 100644 --- a/config/locales/user_mailer/fr.yml +++ b/config/locales/user_mailer/fr.yml @@ -36,6 +36,9 @@ fr: pas pour supprimer votre compte, %{cancel_account_reset}. subject: Supprimer votre compte contact_link_text: communiquez avec nous + doc_auth_link: + message: You've requested to verify your identity on a desktop computer. Please + sign in to %{sp_link} email_changed: help: Si vous préférez ne pas changer votre adresse courriel, veuillez visiter le %{help_link} de %{app} ou %{contact_link}. From 43e7e27a7b1631c4e01a5577717891f61a1de8eb Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Mon, 11 Feb 2019 00:40:57 -0500 Subject: [PATCH 06/10] More specs --- .../idv/doc_auth/mobile_front_image.html.slim | 2 +- config/locales/doc_auth/en.yml | 1 + config/locales/doc_auth/es.yml | 1 + config/locales/doc_auth/fr.yml | 1 + .../doc_auth/mobile_back_image_step_spec.rb | 50 +++++++++++++++++++ .../doc_auth/mobile_front_image_step_spec.rb | 40 +++++++++++++++ spec/jobs/sms_doc_auth_link_job_spec.rb | 43 ++++++++++++++++ spec/support/features/doc_auth_helper.rb | 26 ++++++++++ 8 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 spec/features/idv/doc_auth/mobile_back_image_step_spec.rb create mode 100644 spec/features/idv/doc_auth/mobile_front_image_step_spec.rb create mode 100644 spec/jobs/sms_doc_auth_link_job_spec.rb diff --git a/app/views/idv/doc_auth/mobile_front_image.html.slim b/app/views/idv/doc_auth/mobile_front_image.html.slim index 305e5aa25f0..ab316e097b1 100644 --- a/app/views/idv/doc_auth/mobile_front_image.html.slim +++ b/app/views/idv/doc_auth/mobile_front_image.html.slim @@ -1,6 +1,6 @@ - title t('doc_auth.titles.doc_auth') -h1.h3.mb0 = t('doc_auth.headings.take_pic_back') +h1.h3.mb0 = t('doc_auth.headings.take_pic_front') h5.mt0 = t('doc_auth.instructions.take_pic') ul diff --git a/config/locales/doc_auth/en.yml b/config/locales/doc_auth/en.yml index 15ae728c1d4..b07d649ab67 100644 --- a/config/locales/doc_auth/en.yml +++ b/config/locales/doc_auth/en.yml @@ -20,6 +20,7 @@ en: headings: ssn: Please enter your social security number. take_pic_back: Take a picture of the back of your ID + take_pic_front: Take a picture of the front of your ID take_picture: Take a picture with a phone upload: How would you like to upload your state issued ID? upload_back: Upload an image of the back of your state issued ID diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml index 6312ac5a72c..5d115c9241a 100644 --- a/config/locales/doc_auth/es.yml +++ b/config/locales/doc_auth/es.yml @@ -21,6 +21,7 @@ es: headings: ssn: Por favor ingrese su número de seguro social. take_pic_back: Take a picture of the back of your ID + take_pic_front: Take a picture of the front of your ID take_picture: Take a picture with a phone upload: How would you like to upload your state issued ID? upload_back: Cargue una foto del dorso de su identificación emitida por el estado. diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml index 2a75102364d..81300a994f2 100644 --- a/config/locales/doc_auth/fr.yml +++ b/config/locales/doc_auth/fr.yml @@ -22,6 +22,7 @@ fr: headings: ssn: S'il vous plaît entrez votre numéro de sécurité sociale. take_pic_back: Take a picture of the back of your ID + take_pic_front: Take a picture of the front of your ID take_picture: Take a picture with a phone upload: How would you like to upload your state issued ID? upload_back: S'il vous plaît télécharger une photo du dos de votre ID émis par diff --git a/spec/features/idv/doc_auth/mobile_back_image_step_spec.rb b/spec/features/idv/doc_auth/mobile_back_image_step_spec.rb new file mode 100644 index 00000000000..5a4f38cc83c --- /dev/null +++ b/spec/features/idv/doc_auth/mobile_back_image_step_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +shared_examples 'mobile back image step' do |simulate| + feature 'doc auth mobile back image step' do + include IdvStepHelper + include DocAuthHelper + + before do + allow(Figaro.env).to receive(:acuant_simulator).and_return(simulate) + enable_doc_auth + complete_doc_auth_steps_before_mobile_back_image_step + mock_assure_id_ok + end + + it 'is on the correct page' do + expect(page).to have_current_path(idv_doc_auth_mobile_back_image_step) + expect(page).to have_content(t('doc_auth.headings.take_pic_back')) + end + + it 'proceeds to the next page with valid info' do + attach_image + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_ssn_step) + end + + it 'does not proceed to the next page with invalid info' do + allow_any_instance_of(Idv::Acuant::AssureId).to receive(:post_back_image). + and_return([false, '']) + attach_image + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_mobile_back_image_step) unless simulate + end + + it 'does not proceed to the next page with result=2' do + allow_any_instance_of(Idv::Acuant::AssureId).to receive(:results). + and_return([true, assure_id_results_with_result_2]) + attach_image + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_mobile_back_image_step) unless simulate + end + end +end + +feature 'doc auth back image' do + it_behaves_like 'mobile back image step', 'false' + it_behaves_like 'mobile back image step', 'true' +end diff --git a/spec/features/idv/doc_auth/mobile_front_image_step_spec.rb b/spec/features/idv/doc_auth/mobile_front_image_step_spec.rb new file mode 100644 index 00000000000..bce52195fa4 --- /dev/null +++ b/spec/features/idv/doc_auth/mobile_front_image_step_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +shared_examples 'mobile front image step' do |simulate| + feature 'doc auth mobile front image step' do + include IdvStepHelper + include DocAuthHelper + + before do + allow(Figaro.env).to receive(:acuant_simulator).and_return(simulate) + enable_doc_auth + complete_doc_auth_steps_before_mobile_front_image_step + mock_assure_id_ok + end + + it 'is on the correct page' do + expect(page).to have_current_path(idv_doc_auth_mobile_front_image_step) + expect(page).to have_content(t('doc_auth.headings.take_pic_front')) + end + + it 'proceeds to the next page with valid info' do + attach_image + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_mobile_back_image_step) + end + + it 'does not proceed to the next page with invalid info' do + mock_assure_id_fail + attach_image + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_mobile_front_image_step) + end + end +end + +feature 'doc auth front image' do + it_behaves_like 'mobile front image step', 'false' + it_behaves_like 'mobile front image step', 'true' +end diff --git a/spec/jobs/sms_doc_auth_link_job_spec.rb b/spec/jobs/sms_doc_auth_link_job_spec.rb new file mode 100644 index 00000000000..852a48c3bd5 --- /dev/null +++ b/spec/jobs/sms_doc_auth_link_job_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +describe SmsDocAuthLinkJob do + include Features::ActiveJobHelper + include Rails.application.routes.url_helpers + + describe '.perform' do + before do + reset_job_queues + TwilioService::Utils.telephony_service = FakeSms + FakeSms.messages = [] + end + + subject(:perform) do + SmsDocAuthLinkJob.perform_now( + phone: '+1 (888) 555-5555', + link: root_url, + app: 'login.gov', + ) + end + + it 'sends a message to the mobile number', twilio: true do + allow(Figaro.env).to receive(:twilio_messaging_service_sid).and_return('fake_sid') + + TwilioService::Utils.telephony_service = FakeSms + + perform + + messages = FakeSms.messages + + expect(messages.size).to eq(1) + + msg = messages.first + + expect(msg.messaging_service_sid).to eq('fake_sid') + expect(msg.to).to eq('+1 (888) 555-5555') + expect(msg.body). + to eq(I18n.t('jobs.sms_doc_auth_link_job.message', + application: 'login.gov', + sp_link: root_url)) + end + end +end diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index 00a7cbceac3..2c2524f29fd 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -65,10 +65,18 @@ def idv_doc_auth_front_image_step idv_doc_auth_step_path(step: :front_image) end + def idv_doc_auth_mobile_front_image_step + idv_doc_auth_step_path(step: :mobile_front_image) + end + def idv_doc_auth_back_image_step idv_doc_auth_step_path(step: :back_image) end + def idv_doc_auth_mobile_back_image_step + idv_doc_auth_step_path(step: :mobile_back_image) + end + def idv_doc_auth_doc_success_step idv_doc_auth_step_path(step: :doc_success) end @@ -92,6 +100,17 @@ def complete_doc_auth_steps_before_front_image_step(user = user_with_2fa) click_on t('doc_auth.buttons.use_computer') end + def complete_doc_auth_steps_before_mobile_front_image_step(user = user_with_2fa) + complete_doc_auth_steps_before_upload_step(user) + allow(DeviceDetector).to receive(:new).and_return(mobile_device) + click_on t('doc_auth.buttons.use_phone') + end + + def mobile_device + DeviceDetector.new('Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) \ +AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1') + end + def complete_doc_auth_steps_before_ssn_step(user = user_with_2fa) complete_doc_auth_steps_before_back_image_step(user) attach_image @@ -105,6 +124,13 @@ def complete_doc_auth_steps_before_back_image_step(user = user_with_2fa) click_idv_continue end + def complete_doc_auth_steps_before_mobile_back_image_step(user = user_with_2fa) + complete_doc_auth_steps_before_mobile_front_image_step(user) + mock_assure_id_ok + attach_image + click_idv_continue + end + def complete_doc_auth_steps_before_doc_success_step(user = user_with_2fa) complete_doc_auth_steps_before_ssn_step(user) fill_out_ssn_form_ok From d2ace49eb2a73c8810c1848103e6786a919ff19c Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Mon, 11 Feb 2019 01:15:39 -0500 Subject: [PATCH 07/10] Mailer spec --- app/mailers/user_mailer.rb | 2 +- config/locales/user_mailer/en.yml | 1 + config/locales/user_mailer/es.yml | 1 + config/locales/user_mailer/fr.yml | 1 + spec/mailers/user_mailer_spec.rb | 23 +++++++++++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 90ffddce60a..06ac9f61fb5 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -65,6 +65,6 @@ def undeliverable_address(email_address) def doc_auth_desktop_link_to_sp(email_address, application, link) @link = link @application = application - mail(to: email_address, subject: 'Verify your identity on a desktop computer') + mail(to: email_address, subject: t('user_mailer.doc_auth_link.subject')) end end diff --git a/config/locales/user_mailer/en.yml b/config/locales/user_mailer/en.yml index 28c008c9977..50b59fa8eb5 100644 --- a/config/locales/user_mailer/en.yml +++ b/config/locales/user_mailer/en.yml @@ -38,6 +38,7 @@ en: doc_auth_link: message: You've requested to verify your identity on a desktop computer. Please sign in to %{sp_link} + subject: Verify your identity on a desktop computer email_changed: help: If you did not want to change your email address, please visit the %{app} %{help_link} or %{contact_link}. diff --git a/config/locales/user_mailer/es.yml b/config/locales/user_mailer/es.yml index 866ab9805fc..8942b5eaeaa 100644 --- a/config/locales/user_mailer/es.yml +++ b/config/locales/user_mailer/es.yml @@ -39,6 +39,7 @@ es: doc_auth_link: message: You've requested to verify your identity on a desktop computer. Please sign in to %{sp_link} + subject: Verify your identity on a desktop computer email_changed: help: Si no desea cambiar su email, visite el %{app} %{help_link} o el %{contact_link}. intro: El email de su cuenta de %{app} ha sido cambiado. diff --git a/config/locales/user_mailer/fr.yml b/config/locales/user_mailer/fr.yml index 429d09aed82..187bbbac566 100644 --- a/config/locales/user_mailer/fr.yml +++ b/config/locales/user_mailer/fr.yml @@ -39,6 +39,7 @@ fr: doc_auth_link: message: You've requested to verify your identity on a desktop computer. Please sign in to %{sp_link} + subject: Verify your identity on a desktop computer email_changed: help: Si vous préférez ne pas changer votre adresse courriel, veuillez visiter le %{help_link} de %{app} ou %{contact_link}. diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 18109a60e12..d2b3e142e82 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -275,6 +275,29 @@ def expect_email_body_to_have_help_and_contact_links end end + describe 'doc_auth_desktop_link_to_sp' do + let(:app) { 'login.gov' } + let(:link) { root_url } + let(:mail) { UserMailer.doc_auth_desktop_link_to_sp(email_address.email, app, link) } + + it_behaves_like 'a system email' + + it 'sends to the current email' do + expect(mail.to).to eq [email_address.email] + end + + it 'renders the subject' do + expect(mail.subject).to eq t('user_mailer.doc_auth_link.subject') + end + + it 'renders the body' do + expect(mail.html_part.body).to have_link(app, href: link) + + expect(mail.html_part.body).to \ + have_content(strip_tags(I18n.t('user_mailer.doc_auth_link.message', sp_link: nil))) + end + end + def strip_tags(str) ActionController::Base.helpers.strip_tags(str) end From dc6e44d0c621341c7ea318374a8ec5c4297e637f Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Mon, 11 Feb 2019 01:29:11 -0500 Subject: [PATCH 08/10] Removed unused code --- app/services/idv/flows/doc_auth_flow.rb | 4 ---- .../idv/presenters/doc_auth_presenter.rb | 16 ---------------- app/services/idv/steps/send_link_step.rb | 10 ++++++---- app/services/idv/steps/upload_step.rb | 10 ++++++---- spec/support/features/doc_auth_helper.rb | 5 +++++ 5 files changed, 17 insertions(+), 28 deletions(-) delete mode 100644 app/services/idv/presenters/doc_auth_presenter.rb diff --git a/app/services/idv/flows/doc_auth_flow.rb b/app/services/idv/flows/doc_auth_flow.rb index 8bb0209a8d6..e801e329741 100644 --- a/app/services/idv/flows/doc_auth_flow.rb +++ b/app/services/idv/flows/doc_auth_flow.rb @@ -20,10 +20,6 @@ class DocAuthFlow < Flow::BaseFlow reset: Idv::Actions::ResetAction, }.freeze - PRESENTERS = { - front_image: Idv::Presenters::DocAuthPresenter, - }.freeze - attr_reader :idv_session # this is needed to support (and satisfy) the current LOA3 flow def initialize(session, current_user, name) diff --git a/app/services/idv/presenters/doc_auth_presenter.rb b/app/services/idv/presenters/doc_auth_presenter.rb deleted file mode 100644 index 0076e8d6b2d..00000000000 --- a/app/services/idv/presenters/doc_auth_presenter.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Idv - module Presenters - class DocAuthPresenter - def initialize(session, request, params) - @session = session - @request = request - @params = params - end - - def mobile? - client = DeviceDetector.new(@request.user_agent) - client.device_type != 'desktop' - end - end - end -end diff --git a/app/services/idv/steps/send_link_step.rb b/app/services/idv/steps/send_link_step.rb index 78f5ad2b937..8d8106062f7 100644 --- a/app/services/idv/steps/send_link_step.rb +++ b/app/services/idv/steps/send_link_step.rb @@ -16,13 +16,15 @@ def form_submit end def link - current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. - return_to_sp_url || root_url + identity&.return_to_sp_url || root_url end def app - current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. - friendly_name || 'login.gov' + identity&.friendly_name || 'login.gov' + end + + def identity + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first end end end diff --git a/app/services/idv/steps/upload_step.rb b/app/services/idv/steps/upload_step.rb index 0a6c99d7eb6..13a997cb30d 100644 --- a/app/services/idv/steps/upload_step.rb +++ b/app/services/idv/steps/upload_step.rb @@ -17,14 +17,16 @@ def mobile? client.device_type != 'desktop' end + def identity + current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first + end + def link - current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. - return_to_sp_url || root_url + identity&.return_to_sp_url || root_url end def application - current_user&.identities&.order('created_at DESC')&.limit(1)&.map(&:decorate)&.first&. - friendly_name || 'login.gov' + identity&.friendly_name || 'login.gov' end def mobile_to_desktop diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index 2c2524f29fd..5baecf2ba3b 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -151,6 +151,11 @@ def complete_doc_auth_steps_before_self_image_step(user = user_with_2fa) click_idv_continue end + def complete_doc_auth_steps_before_send_link_step(user = user_with_2fa) + complete_doc_auth_steps_before_upload_step(user) + click_on t('doc_auth.buttons.use_phone') + end + def mock_assure_id_ok allow_any_instance_of(Idv::Acuant::AssureId).to receive(:create_document). and_return([true, '123']) From 0c4a80a4926347613c6c32b16292c41e6cfbd9fe Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Mon, 11 Feb 2019 01:49:27 -0500 Subject: [PATCH 09/10] Last spec --- .../idv/doc_auth/send_link_step_spec.rb | 31 +++++++++++++++++++ spec/support/features/doc_auth_helper.rb | 8 +++++ 2 files changed, 39 insertions(+) create mode 100644 spec/features/idv/doc_auth/send_link_step_spec.rb diff --git a/spec/features/idv/doc_auth/send_link_step_spec.rb b/spec/features/idv/doc_auth/send_link_step_spec.rb new file mode 100644 index 00000000000..9649ab0ef9e --- /dev/null +++ b/spec/features/idv/doc_auth/send_link_step_spec.rb @@ -0,0 +1,31 @@ +require 'rails_helper' + +feature 'doc auth send link step' do + include IdvStepHelper + include DocAuthHelper + + before do + TwilioService::Utils.telephony_service = FakeSms + enable_doc_auth + complete_doc_auth_steps_before_send_link_step + end + + it 'is on the correct page' do + expect(page).to have_current_path(idv_doc_auth_send_link_step) + expect(page).to have_content(t('doc_auth.headings.take_picture')) + end + + it 'proceeds to the next page with valid info' do + fill_in :doc_auth_phone, with: '415-555-0199' + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_link_sent_step) + end + + it 'does not proceed to the next page with invalid info' do + fill_in :doc_auth_phone, with: '' + click_idv_continue + + expect(page).to have_current_path(idv_doc_auth_send_link_step) + end +end diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index 5baecf2ba3b..b7bd310c987 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -89,6 +89,14 @@ def idv_doc_auth_self_image_step idv_doc_auth_step_path(step: :self_image) end + def idv_doc_auth_send_link_step + idv_doc_auth_step_path(step: :send_link) + end + + def idv_doc_auth_link_sent_step + idv_doc_auth_step_path(step: :link_sent) + end + def complete_doc_auth_steps_before_upload_step(user = user_with_2fa) sign_in_and_2fa_user(user) visit idv_doc_auth_welcome_step unless current_path == idv_doc_auth_welcome_step From b2a5b915bb228b6a27705636ab3c6ba85a01ff20 Mon Sep 17 00:00:00 2001 From: Steve Urciuoli Date: Mon, 11 Feb 2019 02:17:52 -0500 Subject: [PATCH 10/10] Mobile to desktop spec --- config/locales/doc_auth/en.yml | 4 ++-- config/locales/doc_auth/es.yml | 4 ++-- config/locales/doc_auth/fr.yml | 4 ++-- .../idv/doc_auth/email_sent_step_spec.rb | 18 ++++++++++++++++++ spec/support/features/doc_auth_helper.rb | 10 ++++++++++ 5 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 spec/features/idv/doc_auth/email_sent_step_spec.rb diff --git a/config/locales/doc_auth/en.yml b/config/locales/doc_auth/en.yml index b07d649ab67..4ca882c9b38 100644 --- a/config/locales/doc_auth/en.yml +++ b/config/locales/doc_auth/en.yml @@ -49,8 +49,8 @@ en: bullet2: Confirm your address bullet3: Secure your account bullet4: Account recovery - email_sent: Link sent to %{email}. Please check your desktop email and follow - instructions to complete the proofing process + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to verify your identity. send_sms: We'll send a text message to your device with a link. Follow that link to your browser to take pictures of the front and back of your ID. take_pic: 'For best results:' diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml index 5d115c9241a..2f0a5e26121 100644 --- a/config/locales/doc_auth/es.yml +++ b/config/locales/doc_auth/es.yml @@ -51,8 +51,8 @@ es: bullet2: Confirm your address bullet3: Secure your account bullet4: Account recovery - email_sent: Link sent to %{email}. Please check your desktop email and follow - instructions to complete the proofing process + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to verify your identity. send_sms: We'll send a text message to your device with a link. Follow that link to your browser to take pictures of the front and back of your ID. take_pic: 'For best results:' diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml index 81300a994f2..3044a71c599 100644 --- a/config/locales/doc_auth/fr.yml +++ b/config/locales/doc_auth/fr.yml @@ -53,8 +53,8 @@ fr: bullet2: Confirm your address bullet3: Secure your account bullet4: Account recovery - email_sent: Link sent to %{email}. Please check your desktop email and follow - instructions to complete the proofing process + email_sent: Link sent to %{email}. Please check your desktop email and follow + instructions to verify your identity. send_sms: We'll send a text message to your device with a link. Follow that link to your browser to take pictures of the front and back of your ID. take_pic: 'For best results:' diff --git a/spec/features/idv/doc_auth/email_sent_step_spec.rb b/spec/features/idv/doc_auth/email_sent_step_spec.rb new file mode 100644 index 00000000000..52ac1337f7a --- /dev/null +++ b/spec/features/idv/doc_auth/email_sent_step_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +feature 'doc auth email sent step' do + include IdvStepHelper + include DocAuthHelper + + let(:user) { user_with_2fa } + + before do + enable_doc_auth + complete_doc_auth_steps_before_email_sent_step(user) + end + + it 'is on the correct page' do + expect(page).to have_current_path(idv_doc_auth_email_sent_step) + expect(page).to have_content(t('doc_auth.instructions.email_sent', email: user.email)) + end +end diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index b7bd310c987..2837b4364f9 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -97,6 +97,10 @@ def idv_doc_auth_link_sent_step idv_doc_auth_step_path(step: :link_sent) end + def idv_doc_auth_email_sent_step + idv_doc_auth_step_path(step: :email_sent) + end + def complete_doc_auth_steps_before_upload_step(user = user_with_2fa) sign_in_and_2fa_user(user) visit idv_doc_auth_welcome_step unless current_path == idv_doc_auth_welcome_step @@ -164,6 +168,12 @@ def complete_doc_auth_steps_before_send_link_step(user = user_with_2fa) click_on t('doc_auth.buttons.use_phone') end + def complete_doc_auth_steps_before_email_sent_step(user = user_with_2fa) + allow(DeviceDetector).to receive(:new).and_return(mobile_device) + complete_doc_auth_steps_before_upload_step(user) + click_on t('doc_auth.buttons.use_computer') + end + def mock_assure_id_ok allow_any_instance_of(Idv::Acuant::AssureId).to receive(:create_document). and_return([true, '123'])