Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7ff4bea
LG-7086-log-whether-account-is-in-reproofing (#7279)
gsa-manish Nov 7, 2022
e3ae3cc
Remove transient Event#diavowal_token, return it as a tuple (#7305)
zachmargolis Nov 7, 2022
92c73f1
Microoptimize reproof_for_irs to avoid database query (#7307)
aduth Nov 8, 2022
79fd388
Drop large user_id, last_sign_in_at DESC index on email_addresses (#7…
Nov 8, 2022
a799b36
Upgrade NewRelic (#7313)
Nov 8, 2022
b88a078
Update phone language on IDV Getting Started screen (#7306)
matthinz Nov 8, 2022
f148121
Adding attempt events packaging batch job. (#7259)
Rwolfe-Nava Nov 8, 2022
85efb64
Stop writing, reading sp_monthly_auths_count (LG-8029) (#7312)
zachmargolis Nov 8, 2022
000c920
LG-8010 | Start to just return JWEs (#7204)
n1zyy Nov 8, 2022
1ffc547
LG 7912: Create controller for fetching addresses from ArcgisApi (#7…
allthesignals Nov 8, 2022
9e0a099
LG-7947: Remove "top" position option for password toggle (#7285)
aduth Nov 8, 2022
4222bc1
Add connection pools for Pinpoint SMS, Voice senders (#7314)
zachmargolis Nov 8, 2022
2c66a27
LG-8050 | Attempts API timestamp parsing fix (#7316)
n1zyy Nov 8, 2022
3e8d252
Revert "Remove concurrency limits from scheduled cron jobs in GoodJob…
zachmargolis Nov 8, 2022
f577eac
Re-enable GoodJob's preserve_old_records (#7320)
zachmargolis Nov 8, 2022
1d4ba73
Update Attempts API filename checksum, checksum file after base16 enc…
zachmargolis Nov 9, 2022
6756096
LG-7819: Modify enrollment creation CLI tool to create enrollments in…
NavaTim Nov 9, 2022
f55ac1d
Jskinne3 rdp2 (#7309)
jskinne3 Nov 9, 2022
f291b80
Drop unused reports (LG-8028) (#7311)
zachmargolis Nov 9, 2022
b77ccec
LG-8044 De-duplicate email_confirmation event (#7319)
ThatSpaceGuy Nov 9, 2022
58ef8e2
LG-7949: Change behavior of "skip to content link" on account page (#…
jc-gsa Nov 9, 2022
c0eab9e
Merge remote-tracking branch 'origin/stages/prod' into stages/rc-2022…
Nov 10, 2022
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 Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ GEM
net-protocol
timeout
net-ssh (6.1.0)
newrelic_rpm (8.8.0)
newrelic_rpm (8.12.0)
nio4r (2.5.8)
nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
Expand Down
16 changes: 3 additions & 13 deletions app/assets/stylesheets/components/_password-toggle.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
lg-password-toggle {
display: block;
position: relative;

&.password-toggle--toggle-top .password-toggle__toggle-label {
@include u-pin-right;
top: -24px;
.validated-field__input-wrapper {
margin-bottom: 0;
}

&.password-toggle--toggle-bottom .validated-field__input-wrapper {
margin-bottom: units(2);
}
}

.password-toggle__toggle-wrapper {
display: flex;
justify-content: end;
}

.password-toggle__toggle-label.usa-checkbox__label {
@include u-margin-y(0);
@include u-padding-y(1);
}
30 changes: 14 additions & 16 deletions app/components/password_toggle_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
<%= content_tag(:'lg-password-toggle', class: css_class) do %>
<%= content_tag(:'lg-password-toggle', **tag_options) do %>
<%= render ValidatedFieldComponent.new(
form: form,
name: :password,
type: :password,
label: label,
label: default_label,
**field_options,
input_html: field_options[:input_html].to_h.merge(
id: input_id,
class: ['password-toggle__input', *field_options.dig(:input_html, :class)],
),
) %>
<div class="password-toggle__toggle-wrapper js">
<input
id="<%= toggle_id %>"
type="checkbox"
class="usa-checkbox__input usa-checkbox__input--bordered password-toggle__toggle"
aria-controls="<%= input_id %>"
>
<label
for="<%= toggle_id %>"
class="usa-checkbox__label password-toggle__toggle-label"
>
<%= toggle_label %>
</label>
</div>
<input
id="<%= toggle_id %>"
type="checkbox"
class="usa-checkbox__input password-toggle__toggle"
aria-controls="<%= input_id %>"
>
<label
for="<%= toggle_id %>"
class="usa-checkbox__label password-toggle__toggle-label"
>
<%= toggle_label %>
</label>
<% end %>
16 changes: 6 additions & 10 deletions app/components/password_toggle_component.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
class PasswordToggleComponent < BaseComponent
attr_reader :form, :label, :toggle_label, :toggle_position, :field_options
attr_reader :form, :label, :toggle_label, :field_options, :tag_options

def initialize(
form:,
label: t('components.password_toggle.label'),
toggle_label: t('components.password_toggle.toggle_label'),
toggle_position: :top,
**field_options
field_options: {},
**tag_options
)
@form = form
@label = label
@toggle_label = toggle_label
@toggle_position = toggle_position
@field_options = field_options
@tag_options = tag_options
end

def css_class
classes = []
classes << 'password-toggle--toggle-top' if toggle_position == :top
classes << 'password-toggle--toggle-bottom' if toggle_position == :bottom
classes
def default_label
t('components.password_toggle.label')
end

def toggle_id
Expand Down
23 changes: 11 additions & 12 deletions app/controllers/api/irs_attempts_api_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def create

headers['X-Payload-Key'] = Base64.strict_encode64(result.encrypted_key)
headers['X-Payload-IV'] = Base64.strict_encode64(result.iv)
send_data Base64.strict_encode64(result.encrypted_data),

send_data result.encrypted_data,
disposition: "filename=#{result.filename}"
else
render json: { status: :unprocessable_entity, description: 'Invalid timestamp parameter' },
Expand All @@ -42,25 +43,21 @@ def authenticate_client
end
end

# @return [Array<String>] JWE strings
def security_event_tokens
return {} unless timestamp
return [] unless timestamp

events = redis_client.read_events(timestamp: timestamp)
sets = {}
events.each_pair do |k, v|
key_id, jti = k.split(':')
sets[jti] = { key_id => v }
end
sets
events.values
end

def encrypted_security_event_log_result
json = security_event_tokens.to_json
events = security_event_tokens.join("\r\n")
decoded_key_der = Base64.strict_decode64(IdentityConfig.store.irs_attempt_api_public_key)
pub_key = OpenSSL::PKey::RSA.new(decoded_key_der)

IrsAttemptsApi::EnvelopeEncryptor.encrypt(
data: json, timestamp: timestamp, public_key: pub_key,
data: events, timestamp: timestamp, public_key: pub_key,
)
end

Expand All @@ -74,7 +71,7 @@ def valid_auth_tokens

def analytics_properties
{
rendered_event_count: security_event_tokens.keys.count,
rendered_event_count: security_event_tokens.count,
timestamp: timestamp&.iso8601,
success: timestamp.present?,
}
Expand All @@ -84,7 +81,9 @@ def timestamp
timestamp_param = params.permit(:timestamp)[:timestamp]
return nil if timestamp_param.nil?

Time.strptime(timestamp_param, '%Y-%m-%dT%H:%M:%S%z')
date_fmt = timestamp_param.include?('.') ? '%Y-%m-%dT%H:%M:%S.%N%z' : '%Y-%m-%dT%H:%M:%S%z'

Time.strptime(timestamp_param, date_fmt)
rescue ArgumentError
nil
end
Expand Down
9 changes: 0 additions & 9 deletions app/controllers/concerns/billable_event_trackable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,13 @@ def track_billing_events
if current_session_has_been_billed?
create_sp_return_log(billable: false)
else
increment_sp_monthly_auths
create_sp_return_log(billable: true)
mark_current_session_billed
end
end

private

def increment_sp_monthly_auths
MonthlySpAuthCount.increment(
user_id: current_user.id,
service_provider: current_sp,
ial: sp_session_ial,
)
end

def create_sp_return_log(billable:)
user_ial_context = IalContext.new(
ial: ial_context.ial, service_provider: current_sp, user: current_user,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,10 @@ def phone_confirmed
end

def send_phone_added_email
event = create_user_event_with_disavowal(:phone_added, current_user)
_event, disavowal_token = create_user_event_with_disavowal(:phone_added, current_user)
current_user.confirmed_email_addresses.each do |email_address|
UserMailer.with(user: current_user, email_address: email_address).
phone_added(disavowal_token: event.disavowal_token).deliver_now_or_later
phone_added(disavowal_token: disavowal_token).deliver_now_or_later
end
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/concerns/unconfirmed_user_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ def track_user_already_confirmed_event
def stop_if_invalid_token
result = email_confirmation_token_validator.submit
analytics.user_registration_email_confirmation(**result.to_h)
return if result.success?
irs_attempts_api_tracker.user_registration_email_confirmation(
email: @email_address&.email,
success: result.success?,
success: false,
failure_reason: irs_attempts_api_tracker.parse_failure_reason(result),
)
return if result.success?
process_unsuccessful_confirmation
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/idv/gpo_verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ def create
if result.extra[:pending_in_person_enrollment]
redirect_to idv_in_person_ready_to_verify_url
else
event = create_user_event_with_disavowal(:account_verified)
event, disavowal_token = create_user_event_with_disavowal(:account_verified)
UserAlerts::AlertUserAboutAccountVerified.call(
user: current_user,
date_time: event.created_at,
sp_name: decorated_session.sp_name,
disavowal_token: event.disavowal_token,
disavowal_token: disavowal_token,
)
flash[:success] = t('account.index.verification.success')
redirect_to sign_up_completed_url
Expand Down
31 changes: 31 additions & 0 deletions app/controllers/idv/in_person/address_search_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Idv
module InPerson
class AddressSearchController < ApplicationController
include RenderConditionConcern

check_or_render_not_found -> { IdentityConfig.store.arcgis_search_enabled }

def index
render json: addresses
end

protected

def addresses
suggestion = geocoder.suggest(permitted_params[:address]).first
return [] unless suggestion
geocoder.find_address_candidates(suggestion.magic_key).slice(0, 1)
rescue Faraday::ConnectionFailed
[]
end

def geocoder
@geocoder ||= ArcgisApi::Geocoder.new
end

def permitted_params
params.permit(:address)
end
end
end
end
4 changes: 2 additions & 2 deletions app/controllers/idv/review_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ def init_profile
end

if idv_session.profile.active?
event = create_user_event_with_disavowal(:account_verified)
event, disavowal_token = create_user_event_with_disavowal(:account_verified)
UserAlerts::AlertUserAboutAccountVerified.call(
user: current_user,
date_time: event.created_at,
sp_name: decorated_session.sp_name,
disavowal_token: event.disavowal_token,
disavowal_token: disavowal_token,
)
end
end
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/sign_up/email_confirmations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def clear_setup_piv_cac_from_sign_in

def process_successful_confirmation
process_valid_confirmation_token
irs_attempts_api_tracker.user_registration_email_confirmation(
email: @email_address&.email,
success: true,
failure_reason: nil,
)
request_id = params.fetch(:_request_id, '')
redirect_to sign_up_enter_password_url(
request_id: request_id, confirmation_token: @confirmation_token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,17 @@ def presenter_for_two_factor_authentication_method

def handle_result(result)
if result.success?
event = create_user_event_with_disavowal(:personal_key_used)
alert_user_about_personal_key_sign_in(event)
_event, disavowal_token = create_user_event_with_disavowal(:personal_key_used)
alert_user_about_personal_key_sign_in(disavowal_token)
generate_new_personal_key_for_verified_users_otherwise_retire_the_key_and_ensure_two_mfa
handle_valid_otp
else
handle_invalid_otp(context: context, type: 'personal_key')
end
end

def alert_user_about_personal_key_sign_in(event)
response = UserAlerts::AlertUserAboutPersonalKeySignIn.call(
current_user, event.disavowal_token
)
def alert_user_about_personal_key_sign_in(disavowal_token)
response = UserAlerts::AlertUserAboutPersonalKeySignIn.call(current_user, disavowal_token)
analytics.personal_key_alert_about_sign_in(**response.to_h)
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/users/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ def send_password_reset_risc_event
end

def create_event_and_notify_user_about_password_change
event = create_user_event_with_disavowal(:password_changed)
UserAlerts::AlertUserAboutPasswordChange.call(current_user, event.disavowal_token)
_event, disavowal_token = create_user_event_with_disavowal(:password_changed)
UserAlerts::AlertUserAboutPasswordChange.call(current_user, disavowal_token)
end

def handle_invalid_password
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/users/reset_passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ def handle_unsuccessful_password_reset(result)
end

def create_reset_event_and_send_notification
event = create_user_event_with_disavowal(:password_changed, resource)
UserAlerts::AlertUserAboutPasswordChange.call(resource, event.disavowal_token)
_event, disavowal_token = create_user_event_with_disavowal(:password_changed, resource)
UserAlerts::AlertUserAboutPasswordChange.call(resource, disavowal_token)
end

def user_params
Expand Down
2 changes: 1 addition & 1 deletion app/decorators/user_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ def identity_verified?(service_provider: nil)
end

def reproof_for_irs?(service_provider:)
return false unless user.active_profile.present?
return false unless service_provider&.irs_attempts_api_enabled
return false unless user.active_profile.present?
!user.active_profile.initiating_service_provider&.irs_attempts_api_enabled
end

Expand Down
30 changes: 30 additions & 0 deletions app/jobs/irs_attempts_events_batch_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class IrsAttemptsEventsBatchJob < ApplicationJob
queue_as :default

def perform(timestamp: Time.zone.now - 1.hour, dir_path: './attempts_api_output')
return nil unless IdentityConfig.store.irs_attempt_api_enabled

events = IrsAttemptsApi::RedisClient.new.read_events(timestamp: timestamp)
event_values = events.values.join("\r\n")

decoded_key_der = Base64.strict_decode64(IdentityConfig.store.irs_attempt_api_public_key)
pub_key = OpenSSL::PKey::RSA.new(decoded_key_der)

result = IrsAttemptsApi::EnvelopeEncryptor.encrypt(
data: event_values, timestamp: timestamp, public_key: pub_key,
)

# write to a file and store on the disk until S3 is setup
FileUtils.mkdir_p(dir_path)

file_path = "#{dir_path}/#{result.filename}"

File.open(file_path, 'wb') do |file|
file.write(result.encrypted_data)
end

return { encryptor_result: result, file_path: file_path }

# Write the file to S3 instead of whatever dir_path winds up being
end
end
Loading