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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,13 @@ If you'd like to work with the previous implementation see the [Docker documenta

### Linting

Run `make lint`
Run `make lint` to look for errors; `make lintfix` can repair some linting errors.

### Configuration variables

Default configuration values — like feature flags, timeout settings, and third-party connection details — are found in [`config/application.yml.default`](config/application.yml/default). From these defaults the file `config/application.yml` is created during `make setup` for use during local development. [See the handbook](https://handbook.login.gov/articles/appdev-secrets-configuration.html).

In deployed environments, configuration values are managed with the [app-s3-secret](https://github.com/18F/identity-devops/blob/main/bin/app-s3-secret) script. [See the handbook](https://handbook.login.gov/articles/devops-scripts.html#app-s3-secret).

### Running jobs

Expand Down
17 changes: 7 additions & 10 deletions app/components/memorable_date_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
false,
) %>
<lg-validated-field>
<lg-validated-field error-id="validated-field-error-<%= unique_id %>">
<%= f.simple_fields_for name do |p| %>
<%= p.input(
:month,
Expand All @@ -33,23 +33,22 @@
maxLength: 2,
aria: {
invalid: false,
describedby: "validated-field-error-#{unique_id}",
labelledby: [
"memorable-date-month-label-#{unique_id}",
"memorable-date-month-hint-#{unique_id}",
],
},
value: month,
},
error: { id: "validated-field-error-#{unique_id}" },
error: false,
required: required,
) %>
<% end %>
<span id=<%= "memorable-date-month-hint-#{unique_id}" %> class="display-none">
<%= t('in_person_proofing.form.state_id.date_hint.month') %>
</span>
</lg-validated-field>
<lg-validated-field>
<lg-validated-field error-id="validated-field-error-<%= unique_id %>">
<%= f.simple_fields_for name do |p| %>
<%= p.input(
:day,
Expand All @@ -67,23 +66,22 @@
maxLength: 2,
aria: {
invalid: false,
describedby: "validated-field-error-#{unique_id}",
labelledby: [
"memorable-date-day-label-#{unique_id}",
"memorable-date-day-hint-#{unique_id}",
],
},
value: day,
},
error: { id: "validated-field-error-#{unique_id}" },
error: false,
required: required,
) %>
<% end %>
<span id=<%= "memorable-date-day-hint-#{unique_id}" %> class="display-none">
<%= t('in_person_proofing.form.state_id.date_hint.day') %>
</span>
</lg-validated-field>
<lg-validated-field>
<lg-validated-field error-id="validated-field-error-<%= unique_id %>">
<%= f.simple_fields_for name do |p| %>
<%= p.input(
:year,
Expand All @@ -101,15 +99,14 @@
maxLength: 4,
aria: {
invalid: false,
describedby: "validated-field-error-#{unique_id}",
labelledby: [
"memorable-date-year-label-#{unique_id}",
"memorable-date-year-hint-#{unique_id}",
],
},
value: year,
},
error: { id: "validated-field-error-#{unique_id}" },
error: false,
required: required,
) %>
<% end %>
Expand All @@ -119,4 +116,4 @@
</lg-validated-field>
</div>
<% end -%>
<div class="usa-error-message" id="validated-field-error-<%= unique_id %>" style="display:none;"></div>
<div id="validated-field-error-<%= unique_id %>" class="usa-error-message display-none"></div>
16 changes: 5 additions & 11 deletions app/components/validated_field_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<lg-validated-field>
<%= content_tag(:'lg-validated-field', 'error-id': error_id) do %>
<%= content_tag(
:script,
error_messages.to_json,
Expand All @@ -18,17 +18,11 @@
class: [*tag_options.dig(:input_html, :class), 'validated-field__input'],
aria: {
invalid: false,
describedby: [
*tag_options.dig(:input_html, :aria, :describedby),
"validated-field-error-#{unique_id}",
"validated-field-hint-#{unique_id}",
],
describedby: aria_describedby_idrefs,
},
},
hint_html: {
id: "validated-field-hint-#{unique_id}",
},
error_html: { id: "validated-field-error-#{unique_id}" },
hint_html: { id: hint_id },
error_html: { id: error_id },
),
) %>
</lg-validated-field>
<% end %>
23 changes: 23 additions & 0 deletions app/components/validated_field_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,31 @@ def error_messages
}.compact
end

def aria_describedby_idrefs
idrefs = [*tag_options.dig(:input_html, :aria, :describedby)]
idrefs << error_id if has_errors?
idrefs << hint_id if has_hint?
idrefs
end

private

def has_errors?
form.object.respond_to?(:errors) && form.object.errors.key?(name)
end

def has_hint?
tag_options.key?(:hint)
end

def error_id
"validated-field-error-#{unique_id}"
end

def hint_id
"validated-field-hint-#{unique_id}"
end

def value_missing_error_message
case input_type
when :boolean
Expand Down
16 changes: 16 additions & 0 deletions app/controllers/concerns/threatmetrix_review_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module ThreatmetrixReviewConcern
extend ActiveSupport::Concern

def handle_pending_threatmetrix_review
redirect_to_threatmetrix_review if threatmetrix_review_pending?
end

def redirect_to_threatmetrix_review
redirect_to idv_setup_errors_url
end

def threatmetrix_review_pending?
return false unless user_fully_authenticated?
current_user.decorate.threatmetrix_review_pending?
end
end
2 changes: 2 additions & 0 deletions app/controllers/idv/doc_auth_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Idv
class DocAuthController < ApplicationController
before_action :confirm_two_factor_authenticated
before_action :handle_pending_threatmetrix_review
before_action :redirect_if_pending_profile
before_action :redirect_if_pending_in_person_enrollment
before_action :extend_timeout_using_meta_refresh_for_select_paths
Expand All @@ -9,6 +10,7 @@ class DocAuthController < ApplicationController
include Flow::FlowStateMachine
include Idv::DocumentCaptureConcern
include Idv::ThreatMetrixConcern
include ThreatmetrixReviewConcern

before_action :redirect_if_flow_completed
before_action :override_document_capture_step_csp
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/idv_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ class IdvController < ApplicationController
include IdvSession
include AccountReactivationConcern
include InheritedProofingConcern
include ThreatmetrixReviewConcern

before_action :confirm_two_factor_authenticated
before_action :handle_pending_threatmetrix_review
before_action :profile_needs_reactivation?, only: [:index]

def index
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/openid_connect/authorization_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class AuthorizationController < ApplicationController
include AuthorizationCountConcern
include BillableEventTrackable
include InheritedProofingConcern
include ThreatmetrixReviewConcern

before_action :build_authorize_form_from_params, only: [:index]
before_action :pre_validate_authorize_form, only: [:index]
Expand All @@ -20,6 +21,7 @@ class AuthorizationController < ApplicationController
before_action :bump_auth_count, only: [:index]

def index
return redirect_to_threatmetrix_review if threatmetrix_review_pending_for_ial2_request?
return redirect_to_account_or_verify_profile_url if profile_or_identity_needs_verification?
return redirect_to(sign_up_completed_url) if needs_completion_screen_reason
link_identity_to_service_provider
Expand Down Expand Up @@ -84,6 +86,11 @@ def redirect_to_account_or_verify_profile_url
redirect_to(idv_url) if identity_needs_verification?
end

def threatmetrix_review_pending_for_ial2_request?
return false unless @authorize_form.ial2_or_greater?
threatmetrix_review_pending?
end

def profile_or_identity_needs_verification?
return false unless @authorize_form.ial2_or_greater?
profile_needs_verification? || identity_needs_verification?
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/saml_idp_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class SamlIdpController < ApplicationController
include AuthorizationCountConcern
include BillableEventTrackable
include SecureHeadersConcern
include ThreatmetrixReviewConcern

prepend_before_action :skip_session_load, only: [:metadata, :remotelogout]
prepend_before_action :skip_session_expiration, only: [:metadata, :remotelogout]
Expand All @@ -24,6 +25,7 @@ class SamlIdpController < ApplicationController

def auth
capture_analytics
return redirect_to_threatmetrix_review if threatmetrix_review_pending? && ial2_requested?
return redirect_to_verification_url if profile_or_identity_needs_verification_or_decryption?
return redirect_to(sign_up_completed_url) if needs_completion_screen_reason
if auth_count == 1 && first_visit_for_sp?
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/users/emails_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,13 @@ def retain_confirmed_emails
end

def send_delete_email_notification
# These emails must be delivered now because the EmailAddress record will not exist
# when run asynchronously
@current_confirmed_emails.each do |confirmed_email|
# rubocop:disable IdentityIdp/MailLaterLinter
UserMailer.with(user: current_user, email_address: confirmed_email).
email_deleted.deliver_now_or_later
email_deleted.deliver_now
# rubocop:enable IdentityIdp/MailLaterLinter
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions app/decorators/user_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ def password_reset_profile
profile if profile&.password_reset?
end

def threatmetrix_review_pending?
@threatmetrix_review_pending ||= threatmetrix_review_pending_profile.present?
end

def threatmetrix_review_pending_profile
user.profiles.threatmetrix_review_pending.order(created_at: :desc).first
end

def qrcode(otp_secret_key)
options = {
issuer: APP_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export const ADDRESS_SEARCH_URL = '/api/addresses';
function AddressSearch({ onAddressFound = () => {}, registerField }: AddressSearchProps) {
const validatedFieldRef = useRef<HTMLFormElement | null>(null);
const [unvalidatedAddressInput, setUnvalidatedAddressInput] = useState('');
const [addressQuery, setAddressQuery] = useState({} as Location);
const { t } = useI18n();

const handleAddressSearch = useCallback(
Expand All @@ -32,14 +31,13 @@ function AddressSearch({ onAddressFound = () => {}, registerField }: AddressSear
if (unvalidatedAddressInput === '') {
return;
}
const addressCandidates = await request(ADDRESS_SEARCH_URL, {
const addressCandidates = await request<Location>(ADDRESS_SEARCH_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
json: { address: unvalidatedAddressInput },
});

const bestMatchedAddress = addressCandidates[0];
setAddressQuery(bestMatchedAddress);
onAddressFound(bestMatchedAddress);
},
[unvalidatedAddressInput],
Expand Down Expand Up @@ -68,7 +66,6 @@ function AddressSearch({ onAddressFound = () => {}, registerField }: AddressSear
<Button type="submit" className="margin-y-5" onClick={handleAddressSearch}>
{t('in_person_proofing.body.location.po_search.search_button')}
</Button>
<>{addressQuery.address}</>
</>
);
}
Expand Down
Loading