Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6e130a5
LG-12428: extract_pii_from_doc refactor (#10069)
amirbey Feb 15, 2024
ddc696e
Return a default result from `#resolved_authn_context_result` when no…
jmhooper Feb 15, 2024
33283ca
Bump libphonenumber-js from 1.10.55 to 1.10.56 (#10094)
dependabot[bot] Feb 15, 2024
5cc7504
Ignore frontend errors not originating from application script (#10087)
aduth Feb 15, 2024
8ded9b0
Remove fallback logging for unknown frontend event (#10086)
aduth Feb 15, 2024
da7e341
Fix static usage of error messages that results in them not being unt…
Feb 15, 2024
e9504f7
Parallelize feature spec build, leverage Make up-to-date for browsers…
aduth Feb 15, 2024
996f266
Guarantee uniqueness of MFA spec factory names (#10097)
aduth Feb 15, 2024
4926cdd
Reimplement icon component as SVG image mask (#10065)
aduth Feb 15, 2024
e9537cf
LG-12065 Add "full registered users count" to Monthly Key Metric Repo…
olatifflexion Feb 16, 2024
c60816e
Lg-12150 add vtr and acr_values to identity table (#10102)
theabrad Feb 16, 2024
e479616
changelog: Bug Fixes, Delete Unused Providers, accounting for no inte…
nprimak Feb 16, 2024
0c0854e
barcode attention should only be shown when api image upload submissi…
amirbey Feb 20, 2024
f2d1559
Implement language picker expander as icon (#10098)
aduth Feb 20, 2024
20f08b3
Drop unused monthly_auth_counts table (#10109)
Feb 20, 2024
dea5bb8
LG-12031: Make troubleshooting links consistent with other modules (#…
jc-gsa Feb 20, 2024
2bf5c4b
LG-11897: Send Text on Account Deletion (#10015)
mdiarra3 Feb 20, 2024
ca3c16c
Revert icon reimplementation as inline style (#10113)
aduth Feb 20, 2024
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ brakeman: ## Runs brakeman code security check
(bundle exec brakeman) || (echo "Error: update code as needed to remove security issues. For known exceptions already in brakeman.ignore, use brakeman to interactively update exceptions."; exit 1)

public/packs/manifest.json: yarn.lock $(shell find app/javascript -type f) ## Builds JavaScript assets
yarn build
yarn build:js

browsers.json: yarn.lock .browserslistrc ## Generates browsers.json browser support file
yarn generate-browsers-json
Expand Down
14 changes: 7 additions & 7 deletions app/components/block_link_component.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
class BlockLinkComponent < BaseComponent
attr_reader :url, :action, :new_tab, :tag_options
attr_reader :url, :action, :new_tab, :tag_options, :component

alias_method :new_tab?, :new_tab

def initialize(url:, action: tag.method(:a), new_tab: false, **tag_options)
@action = action
def initialize(url: '#', component: nil, new_tab: false, **tag_options)
@url = url
@component = component
@new_tab = new_tab
@tag_options = tag_options
end
Expand All @@ -21,11 +21,11 @@ def target
end

def wrapper(&block)
wrapper = action.call(**tag_options, href: url, class: css_class, target:, &block)
if wrapper.respond_to?(:render_in)
render wrapper, &block
if component
render component.new(href: url, class: css_class), &block
else
wrapper
action = tag.method(:a)
action.call(**tag_options, href: url, class: css_class, target:, &block)
end
end
end
3 changes: 3 additions & 0 deletions app/components/form_link_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<lg-form-link>
<%= link_to('#', **tag_options) { content } %>
</lg-form-link>
7 changes: 7 additions & 0 deletions app/components/form_link_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class FormLinkComponent < BaseComponent
attr_reader :tag_options

def initialize(**tag_options)
@tag_options = tag_options
end
end
1 change: 1 addition & 0 deletions app/components/form_link_component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@18f/identity-form-link/form-link-element';
16 changes: 11 additions & 5 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,17 @@ def sign_out(*args)
end

def resolved_authn_context_result
@resolved_authn_context_result ||= AuthnContextResolver.new(
service_provider: current_sp,
vtr: sp_session[:vtr],
acr_values: sp_session[:acr_values],
).resolve
return @resolved_authn_context_result if defined?(@resolved_authn_context_result)

if current_sp.nil?
@resolved_authn_context_result = Vot::Parser::Result.no_sp_result
else
@resolved_authn_context_result = AuthnContextResolver.new(
service_provider: current_sp,
vtr: sp_session[:vtr],
acr_values: sp_session[:acr_values],
).resolve
end
end

def context
Expand Down
12 changes: 5 additions & 7 deletions app/controllers/concerns/idv/document_capture_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,16 @@ def failure(message, extra = nil)
FormResponse.new(**form_response_params)
end

# @param [DocAuth::Response,
# DocumentCaptureSessionResult] response
def extract_pii_from_doc(user, response, store_in_session: false)
def extract_pii_from_doc(user, store_in_session: false)
if defined?(idv_session) # hybrid mobile does not have idv_session
idv_session.had_barcode_read_failure = response.attention_with_barcode?
idv_session.had_barcode_read_failure = stored_result.attention_with_barcode?
if store_in_session
idv_session.pii_from_doc = response.pii_from_doc
idv_session.selfie_check_performed = response.selfie_check_performed?
idv_session.pii_from_doc = stored_result.pii_from_doc
idv_session.selfie_check_performed = stored_result.selfie_check_performed?
end
end

track_document_issuing_state(user, response.pii_from_doc[:state])
track_document_issuing_state(user, stored_result.pii_from_doc[:state])
end

def stored_result
Expand Down
9 changes: 4 additions & 5 deletions app/controllers/frontend_log_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,12 @@ class FrontendLogController < ApplicationController
EVENT_MAP = ALLOWED_EVENTS.index_by(&:to_s).merge(LEGACY_EVENT_MAP).freeze

def create
result = frontend_logger.track_event(log_params[:event], log_params[:payload].to_h)
success = frontend_logger.track_event(log_params[:event], log_params[:payload].to_h)

if result
render json: { success: true }, status: :ok
if success
render json: { success: }, status: :ok
else
render json: { success: false, error_message: 'invalid event' },
status: :bad_request
render json: { success:, error_message: 'invalid event' }, status: :bad_request
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/idv/document_capture_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def analytics_arguments
def handle_stored_result
if stored_result&.success? && selfie_requirement_met?
save_proofing_components(current_user)
extract_pii_from_doc(current_user, stored_result, store_in_session: true)
extract_pii_from_doc(current_user, store_in_session: true)
flash[:success] = t('doc_auth.headings.capture_complete')
successful_response
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def analytics_arguments
def handle_stored_result
if stored_result&.success? && selfie_requirement_met?
save_proofing_components(document_capture_user)
extract_pii_from_doc(document_capture_user, stored_result)
extract_pii_from_doc(document_capture_user)
successful_response
else
extra = { stored_result_present: stored_result.present? }
Expand Down
13 changes: 4 additions & 9 deletions app/controllers/idv/link_sent_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def update

# The doc capture flow will have fetched the results already. We need
# to fetch them again here to add the PII to this session
handle_document_verification_success(document_capture_session_result)
handle_document_verification_success
idv_session.redo_document_capture = nil

redirect_to idv_ssn_url
Expand Down Expand Up @@ -63,9 +63,9 @@ def analytics_arguments
}.merge(ab_test_analytics_buckets)
end

def handle_document_verification_success(get_results_response)
def handle_document_verification_success
save_proofing_components(current_user)
extract_pii_from_doc(current_user, get_results_response, store_in_session: true)
extract_pii_from_doc(current_user, store_in_session: true)
idv_session.flow_path = 'hybrid'
end

Expand All @@ -80,12 +80,7 @@ def render_step_incomplete_error
end

def take_photo_with_phone_successful?
document_capture_session_result.present? && document_capture_session_result.success? &&
selfie_requirement_met?
end

def document_capture_session_result
@document_capture_session_result ||= document_capture_session&.load_result
stored_result&.success? && selfie_requirement_met?
end
end
end
12 changes: 12 additions & 0 deletions app/controllers/users/delete_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def delete
irs_attempts_api_tracker.logged_in_account_purged(success: true)
send_push_notifications
notify_user_via_email_of_deletion
notify_user_via_sms_of_deletion
delete_user
sign_out
flash[:success] = t('devise.registrations.destroyed')
Expand Down Expand Up @@ -60,5 +61,16 @@ def notify_user_via_email_of_deletion
end
end
# rubocop:enable IdentityIdp/MailLaterLinter

def notify_user_via_sms_of_deletion
phone_configurations = current_user.phone_configurations
phone_configurations.each do |configuration|
next unless configuration.capabilities.supports_sms?
Telephony.send_account_deleted_notice(
to: configuration.phone,
country_code: Phonelib.parse(configuration.phone).country,
)
end
end
end
end
4 changes: 2 additions & 2 deletions app/forms/openid_connect_logout_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ class OpenidConnectLogoutForm

validates :client_id,
presence: {
message: I18n.t('openid_connect.logout.errors.client_id_missing'),
message: ->(_, _) { I18n.t('openid_connect.logout.errors.client_id_missing') },
},
if: :reject_id_token_hint?
validates :id_token_hint,
absence: {
message: I18n.t('openid_connect.logout.errors.id_token_hint_present'),
message: ->(_, _) { I18n.t('openid_connect.logout.errors.id_token_hint_present') },
},
if: :reject_id_token_hint?
validates :post_logout_redirect_uri, presence: true
Expand Down
10 changes: 10 additions & 0 deletions app/javascript/packages/analytics/is-trackable-error-event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ describe('isTrackableErrorEvent', () => {
});
});

context('with non-javascript filename', () => {
const event = new ErrorEvent('error', {
filename: new URL('foo', window.location.origin).toString(),
});

it('returns false', () => {
expect(isTrackableErrorEvent(event)).to.be.false();
});
});

context('with filename from the same host', () => {
const event = new ErrorEvent('error', {
filename: new URL('foo.js', window.location.origin).toString(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
function isTrackableErrorEvent(event: ErrorEvent): boolean {
try {
return new URL(event.filename).host === window.location.host;
const { host, pathname } = new URL(event.filename);
return host === window.location.host && pathname.endsWith('.js');
} catch {
return false;
}
Expand Down
22 changes: 22 additions & 0 deletions app/javascript/packages/form-link/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# `@18f/identity-form-link`

Custom element for links which submit as a form, supporting non-GET navigation.

## Usage

### Custom Element

Importing the element will register the `<lg-form-link>` custom element:

```ts
import '@18f/identity-form-link/form-link-element';
```

The custom element will implement the link submission behavior, but all markup must already exist.

```html
<lg-form-link>
<a href="https://example.com">Submit</a>
<form method="post" action="https://example.com" class="display-none"></form>
</lg-form-link>
```
28 changes: 28 additions & 0 deletions app/javascript/packages/form-link/form-link-element.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import sinon from 'sinon';
import { getByRole, fireEvent } from '@testing-library/dom';
import './form-link-element';

describe('FormLinkElement', () => {
function createElement() {
document.body.innerHTML = `
<lg-form-link>
<a href="https://example.com">Submit</a>
<form method="post" action="https://example.com" class="display-none"></form>
</lg-form-link>
`;

return document.body.querySelector('lg-form-link')!;
}

it('submits form on link click', () => {
const element = createElement();
const link = getByRole(element, 'link');

const onSubmit = sinon.stub();
element.form.submit = onSubmit;
const didPreventDefault = !fireEvent.click(link);

expect(onSubmit).to.have.been.called();
expect(didPreventDefault).to.be.true();
});
});
30 changes: 30 additions & 0 deletions app/javascript/packages/form-link/form-link-element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class FormLinkElement extends HTMLElement {
connectedCallback() {
this.link.addEventListener('click', this.submit);
}

get form(): HTMLFormElement {
return this.querySelector('form')!;
}

get link(): HTMLAnchorElement {
return this.querySelector('a')!;
}

submit = (event: MouseEvent) => {
event.preventDefault();
this.form.submit();
};
}

declare global {
interface HTMLElementTagNameMap {
'lg-form-link': FormLinkElement;
}
}

if (!customElements.get('lg-form-link')) {
customElements.define('lg-form-link', FormLinkElement);
}

export default FormLinkElement;
8 changes: 8 additions & 0 deletions app/javascript/packages/form-link/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@18f/identity-form-link",
"version": "1.0.0",
"private": true,
"sideEffects": [
"./form-link-element.ts"
]
}
2 changes: 1 addition & 1 deletion app/javascript/packages/phone-input/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "1.0.0",
"dependencies": {
"intl-tel-input": "^17.0.19",
"libphonenumber-js": "^1.10.55"
"libphonenumber-js": "^1.10.56"
},
"sideEffects": [
"./index.ts"
Expand Down
2 changes: 0 additions & 2 deletions app/models/monthly_auth_count.rb

This file was deleted.

6 changes: 4 additions & 2 deletions app/models/phone_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ def masked_phone
def selection_presenters
options = []

capabilities = PhoneNumberCapabilities.new(phone, phone_confirmed: !!confirmed_at?)

if capabilities.supports_sms?
options << TwoFactorAuthentication::SignInPhoneSelectionPresenter.
new(user:, configuration: self, delivery_method: :sms)
Expand All @@ -34,6 +32,10 @@ def selection_presenters
options
end

def capabilities
PhoneNumberCapabilities.new(phone, phone_confirmed: !!confirmed_at?)
end

def friendly_name
:phone
end
Expand Down
1 change: 1 addition & 0 deletions app/presenters/image_upload_response_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def attention_with_barcode?
end

def ocr_pii
return unless success?
return unless attention_with_barcode? && @form_response.respond_to?(:pii_from_doc)
@form_response.pii_from_doc&.slice(:first_name, :last_name, :dob)
end
Expand Down
2 changes: 0 additions & 2 deletions app/services/frontend_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ def track_event(name, attributes)
analytics_method.call(**hash_from_kwargs(attributes, analytics_method))
true
else
# 2023-10-31 - Temporary
analytics.track_event("Frontend (warning): #{name}", attributes)
false
end
end
Expand Down
7 changes: 7 additions & 0 deletions app/services/reporting/total_user_count_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def total_user_count_report
[
['Metric', 'All Users', 'Verified users', 'Time Range Start', 'Time Range End'],
['All-time count', total_user_count, verified_user_count, '-', report_date.to_date],
['All-time fully registered', total_fully_registered, '-', '-', report_date.to_date],
[
'New users count',
new_user_count,
Expand Down Expand Up @@ -45,6 +46,12 @@ def new_user_count
end
end

def total_fully_registered
Reports::BaseReport.transaction_with_timeout do
RegistrationLog.where('registered_at <= ?', end_date).where.not(registered_at: nil).count
end
end

def total_user_count
Reports::BaseReport.transaction_with_timeout do
User.where('created_at <= ?', end_date).count
Expand Down
Loading