Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
1f2b804
Add draft confirmation component
jc-gsa Apr 5, 2023
c0c69e0
Add translations
jc-gsa Apr 6, 2023
314de59
Add various notices
jc-gsa Apr 6, 2023
a229005
Add stash WIP password-confirmation package
jc-gsa Apr 6, 2023
4f1af11
Add spec
jc-gsa Apr 7, 2023
71f861a
Add initial back-end validation
jc-gsa Apr 7, 2023
43b42fa
Add tests
jc-gsa Apr 7, 2023
aea8907
Add refactor
jc-gsa Apr 10, 2023
52099ad
Add PasswordConfirmationForm
jc-gsa Apr 12, 2023
2251943
Update FormPasswordValidator
jc-gsa Apr 12, 2023
ef475a3
Add tests
jc-gsa Apr 12, 2023
43eb800
Update session_helper
jc-gsa Apr 13, 2023
ccc7b11
Add WIP
jc-gsa Apr 13, 2023
f723aa8
Update tests, refactor
jc-gsa Apr 14, 2023
ab97289
Update tests
jc-gsa Apr 14, 2023
5cbf908
Add refactor
jc-gsa Apr 17, 2023
96f726d
Consolidate translation keys
jc-gsa Apr 17, 2023
715baba
Add name changes
jc-gsa Apr 18, 2023
acffb17
Use ActiveSupport cache version 7.0 (#8126)
Apr 4, 2023
f9d5922
LG-8908: Add USPS document check to ProofingComponent when enrollment…
Apr 4, 2023
14b151a
add/lock in saml_2023 references, remove saml_2021 ones (#8122)
bleachbyte Apr 4, 2023
3ace4b0
LG-9026: Additional cleanup (#8127)
matthinz Apr 4, 2023
c1d173e
Combine two versions of `confirm_document_capture_complete` before ac…
soniaconnolly Apr 4, 2023
7cd847b
LG-8932: Fix check for state vs residential address; update test (#8124)
NavaTim Apr 4, 2023
c15a5ca
LG-9146 Fix intermittent infinity loop (#8133)
ThatSpaceGuy Apr 4, 2023
7e36baa
re-add saml2021* files to AppArtifacts.setup, for now (#8129)
bleachbyte Apr 5, 2023
7563cb6
Do not prompt for re-authentication on backup code refresh prompt (#8…
Apr 5, 2023
88f1da0
Use Rack::Session methods when calling redis-session-store (#8132)
Apr 5, 2023
7696d76
LG-9345 Maintain material consistency in IPP pages (#8104)
jack-ryan-nava-pbc Apr 5, 2023
6ac93bd
Ignore unhandled HTTP Verb errors (#8139)
zachmargolis Apr 5, 2023
7826f89
LG-9411 fraud review script fix (#8141)
theabrad Apr 5, 2023
5b329d6
Remove DocumentCaptureController 404 before action (#8128)
soniaconnolly Apr 5, 2023
478dff0
LG-8710: New IDV unavailable screen (#8106)
matthinz Apr 5, 2023
6f4fbd6
LG-9272: Record in-person enrollment status check completion time (#8…
NavaTim Apr 5, 2023
0216ebc
Stop writing data to reports.log (LG-9415) (#8143)
zachmargolis Apr 5, 2023
079c4b4
Remove unused StoreSpMetadataInSession#event_attributes (#8140)
aduth Apr 6, 2023
3c6407d
Update knapsack report (#8144)
zachmargolis Apr 6, 2023
2aa2eeb
LG-9398 Add Fraud Review / Rejection Timestamp Columns (#8142)
eric-gade Apr 6, 2023
a5ee170
Friday test hacking/fix phone rate limiting test (#8116)
jmax-gsa Apr 6, 2023
4bb3302
LG-9237: Collect issuing state on state id page (#8121)
eileen-nava Apr 6, 2023
05e77c8
LG-9237: Send USPS the state instead of jurisdiction from state ID (#…
NavaTim Apr 6, 2023
94eaf45
Add a total users across all SPs to user count reports (LG-9408) (#8135)
zachmargolis Apr 6, 2023
b3c9a60
LG-9238: Test that state id jurisdiction is sent to aamva (#8138)
eileen-nava Apr 6, 2023
3fa583a
Fix error when verifying nil backup code (#8148)
Apr 6, 2023
64ab4a1
Avoid writing .irb_history on deployed boxes (#8147)
zachmargolis Apr 6, 2023
41c1576
LG-9237: Clean up state id translations and legend text (#8150)
eileen-nava Apr 7, 2023
c169da2
Fix 500 error on phone verification warning screen (#8152)
matthinz Apr 7, 2023
b1f7204
LG-9065 Write an exception result when TMx has an invalid review stat…
jmhooper Apr 7, 2023
2123ed5
Return an empty hash from `#flow_session` if it has not been created …
jmhooper Apr 7, 2023
f2ec4de
Maintain request ID in password reset (#8145)
aduth Apr 10, 2023
67cbb1a
Store passed AAL as text to preserve all AAL details (#8012)
Jeremy1026 Apr 10, 2023
521d3a1
Link to idv_address_url from verify_info show template (#8157)
soniaconnolly Apr 10, 2023
aaa38db
LG-9065 Make the DDP result class and proofer responsible for buildin…
jmhooper Apr 10, 2023
3374a05
LG-9426: Update mock DDP proofer results to match the real one (#8155)
matthinz Apr 10, 2023
18e3bbd
LG-9141 Skip address page if same address as ID is true (#8151)
jack-ryan-nava-pbc Apr 10, 2023
4e24dde
Remove unused EmailSent step (#8158)
soniaconnolly Apr 10, 2023
7bd6e2e
Update documentation to remove references to design.login.gov (#8159)
aduth Apr 10, 2023
e77a974
Fix flaky IdV outage spec (#8168)
matthinz Apr 10, 2023
30881a6
LG-9103: capture error when ArcGIS service is not returning a token (…
racingspider Apr 10, 2023
d4878be
Add safer parsing of dynamic SAML urls (LG-8837) (#8166)
zachmargolis Apr 10, 2023
cb34484
LG-9216: A/B test for tabbed Sign In view (#8112)
aduth Apr 11, 2023
0cb8651
Remove request_id parameters from Sign In view links (#8137)
aduth Apr 11, 2023
28435ea
Refactor implicit calculation of two-factor authentication methods (#…
Apr 11, 2023
e6f85fd
Remove phone_confirmed column from profiles table (#8175)
Apr 11, 2023
d6ff2e3
Revert "Add safer parsing of dynamic SAML urls (LG-8837) (#8166)" (#8…
Apr 11, 2023
70ff038
Remove implicit two_factor_authentication_method in favor of explicit…
Apr 11, 2023
ac1cbd5
Remove unused RedoAddressAction (#8165)
soniaconnolly Apr 11, 2023
8f34e11
Update nokogiri to patch reported vulnerability (#8184)
Apr 11, 2023
9cee22f
Temporarily skip IdV outage spec (#8185)
matthinz Apr 11, 2023
5f391d8
Lg 9399 light refactor of profile and spec (#8170)
Apr 11, 2023
0274dfd
LG-9362 Please call page after personal key page in GPO flow (#8156)
theabrad Apr 11, 2023
58fbb63
Add files for Acuant SDK upgrade to v 11.8.1 (#8169)
jskinne3 Apr 11, 2023
a97da7a
Remove saml_internal_post feature flag (#8180)
aduth Apr 12, 2023
4decfc6
LG-9232: Improve the usability of the password page (#8085)
jmdembe Apr 12, 2023
02e1d06
Use the instant verify product instead of the parsed errors for get-t…
jmhooper Apr 12, 2023
bb099e1
LG-9209 Use the ExecutedStepName to group LexisNexis errors (#8177)
jmhooper Apr 12, 2023
4a5bc0a
LG-9065 Include TMx response in the resoltuion result adjudicator log…
jmhooper Apr 12, 2023
d5f25de
LG-9065 Add the ThreatMetrix review status to the result of the resol…
jmhooper Apr 12, 2023
80a16bc
Move `phone_confirmed` removal migration to correct location (#8187)
Apr 12, 2023
586238c
LG-8500: Minor copy update for French and Spanish language selection …
olatifflexion Apr 12, 2023
73b2300
Write to the ThreatMetrix proofing component even if ThreatMetrix is …
jmhooper Apr 12, 2023
e3edafe
Update schema timestamp (#8193)
Apr 12, 2023
fb8eb65
LG-9214: mfa selection priority (#8130)
mdiarra3 Apr 12, 2023
95f320e
Fix incorrect SAML path being called in SAML POST authentication (#8182)
Apr 12, 2023
5dfae0d
Optimize user_fully_authenticated to defer database query (#8194)
aduth Apr 12, 2023
c503653
LG-9463 Add an explicit redirect from personal key controller for GPO…
jmhooper Apr 12, 2023
bb96519
Remove a leftover SSN template from FSM removal (#8196)
jmhooper Apr 12, 2023
94188d1
LG-9161 Remove drivers license verification from instant verify (#8167)
amirbey Apr 12, 2023
dc3c2a9
LG-9431 new CaptureComplete controller (feature flagged) (#8186)
soniaconnolly Apr 12, 2023
893598c
Remove reference to embedded images in LICENSE (#8202)
aduth Apr 13, 2023
3de2a44
Turn README.md into an index of the docs dir (#8198)
zachmargolis Apr 13, 2023
65b2390
Avoid caching for webpack dev server resources (#8205)
aduth Apr 13, 2023
cfe0c08
Re-enable IDV outage feature spec 🤞 (#8188)
matthinz Apr 13, 2023
06dc1dd
Turn SAML year into a path parameter (LG-7554) (#7153)
zachmargolis Apr 13, 2023
8860087
Fix 500 due to undefined two_factor_authentication_method method (#8208)
Apr 13, 2023
ebeda90
Refactor fraud specs (#8201)
Apr 13, 2023
5179986
Refactor fraud specs (#8201)
Apr 13, 2023
0284794
Remove unused configuration redis_throttle_alternate_url and redis_th…
Apr 14, 2023
8406b9b
Override tag style to leave case unchanged and make text bold (#8212)
soniaconnolly Apr 14, 2023
c18273a
LG-9333 Preserve the SSN when returning to the SSN controller (#8197)
jmhooper Apr 14, 2023
7c7e66c
LG-8714 Remove UserDecorator (#8204)
eric-gade Apr 14, 2023
e157d63
Jskinne3 lg 9361 mobile local md (#8217)
jskinne3 Apr 14, 2023
e370cb4
Configure the DDP mock client to respond with a failed result on `no_…
jmhooper Apr 17, 2023
cb5350c
LG-9034 Log TrueID decision product status (#8195)
amirbey Apr 17, 2023
7397f1b
LG-9488: Entry controller for hybrid mobile document capture flow (#8…
matthinz Apr 17, 2023
cc4c0a2
Fix email confirmation 500 (#8224)
Apr 17, 2023
bf471cb
LG-9321: New field on Enrollment Outcomes for GetUspsProofingResultsJ…
gina-yamada Apr 17, 2023
e3f8306
Rename translation tags from combined_upload to upload (#8219)
soniaconnolly Apr 17, 2023
e893a20
LG-9391: Improve accessibility for phone dropdown (#8210)
aduth Apr 18, 2023
fa106df
Upgrade Stylelint to v15, prepare new config publish (#8228)
aduth Apr 18, 2023
2a1e413
LG-9358 Phone Verification Content Changes (#8222)
eric-gade Apr 18, 2023
f779087
Create return_to_sp url directly rather than through FSM for Document…
soniaconnolly Apr 18, 2023
004790e
Jmax/lg 9147 show extra guidance for puerto rico addresses (#8088)
jmax-gsa Apr 18, 2023
7a9331d
refactor to reduce in-person feature test flakes (#8215)
Apr 18, 2023
2732b56
Update package.json
jc-gsa Apr 19, 2023
94c68ad
Merge branch 'main' into LG-9208-confirm-password
jc-gsa Apr 19, 2023
665f564
Add post-merge
jc-gsa Apr 19, 2023
017b3c2
Clear validations
jc-gsa Apr 20, 2023
b3774fc
Add refactor
jc-gsa Apr 24, 2023
ee6881d
Update app/components/password_confirmation_component.html.erb
jc-gsa Apr 25, 2023
a7f58db
Update app/components/password_confirmation_component.html.erb
jc-gsa Apr 25, 2023
8a15d37
Add refactor
jc-gsa Apr 24, 2023
b260d4e
Merge branch 'LG-9208-confirm-password' of github.com:18F/identity-id…
jc-gsa Apr 26, 2023
7974fd7
Add feature flag password_confirmation_enabled
jc-gsa May 1, 2023
28098e9
Merge branch 'main' into LG-9208-confirm-password
jc-gsa May 1, 2023
079938f
Change flag to confirmation_enabled
jc-gsa May 1, 2023
cb00c49
Update app/components/password_confirmation_component.html.erb
jc-gsa May 2, 2023
9a1998a
Add refactor
jc-gsa May 2, 2023
84f21ad
Merge branch 'LG-9208-confirm-password' of github.com:18F/identity-id…
jc-gsa May 2, 2023
622efe8
Yaml
jc-gsa May 2, 2023
a798714
Merge branch 'LG-9208-confirm-password' of github.com:18F/identity-id…
jc-gsa May 2, 2023
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
46 changes: 46 additions & 0 deletions app/components/password_confirmation_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<%= content_tag(:'lg-password-confirmation', **tag_options) do %>
<%= render ValidatedFieldComponent.new(
form: form,
name: :password,
type: :password,
label: default_label,
required: true,
**field_options,
input_html: field_options[:input_html].to_h.merge(
id: input_id,
class: ['password-confirmation__input', *field_options.dig(:input_html, :class)],
),
) %>
<%= render ValidatedFieldComponent.new(
form: form,
name: :password_confirmation,
type: :password_confirmation,
label: confirmation_label,
required: true,
**field_options,
input_html: field_options[:input_html].to_h.merge(
id: input_confirmation_id,
class: ['password-confirmation__input-confirmation', *field_options.dig(:input_html, :class)],
),
wrapper_html: field_options[:wrapper_html].to_h.merge(
class: ['margin-bottom-0', *field_options.dig(:wrapper_html, :class)],
),
error_messages: {
valueMissing: t('components.password_confirmation.errors.empty'),
},
) %>
<input
id="<%= toggle_id %>"
type="checkbox"
class="usa-checkbox__input password-confirmation__toggle"
aria-controls="<%= input_id %> <%= input_confirmation_id %>"
>
<label
for="<%= toggle_id %>"
class="usa-checkbox__label password-confirmation__toggle-label"
>
<%= toggle_label %>
</label>

<%= form.hidden_field :confirmation_enabled, value: true %>
<% end %>
35 changes: 35 additions & 0 deletions app/components/password_confirmation_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class PasswordConfirmationComponent < BaseComponent
attr_reader :form, :toggle_label, :field_options, :tag_options

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

def default_label
t('forms.password')
end

def confirmation_label
t('components.password_confirmation.confirm_label')
end

def toggle_id
"password-confirmation-toggle-#{unique_id}"
end

def input_id
"password-confirmation-input-#{unique_id}"
end

def input_confirmation_id
"password-confirmation-input-confirmation-#{unique_id}"
end
end
1 change: 1 addition & 0 deletions app/components/password_confirmation_component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@18f/identity-password-confirmation/password-confirmation-element';
24 changes: 17 additions & 7 deletions app/controllers/sign_up/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ def new

def create
result = password_form.submit(permitted_params)
analytics.password_creation(**result.to_h)
irs_attempts_api_tracker.user_registration_password_submitted(
success: result.success?,
failure_reason: irs_attempts_api_tracker.parse_failure_reason(result),
)

track_analytics(result)

if result.success?
process_successful_password_creation
Expand All @@ -41,8 +38,21 @@ def render_page
)
end

def track_analytics(result)
failure_reason = irs_attempts_api_tracker.parse_failure_reason(result)

analytics.password_creation(**result.to_h)
irs_attempts_api_tracker.user_registration_password_submitted(
success: result.success?,
failure_reason: failure_reason,
)
end

def permitted_params
params.require(:password_form).permit(:confirmation_token, :password)
params.require(:password_form).permit(
:confirmation_token, :password, :password_confirmation,
:confirmation_enabled
)
end

def process_successful_password_creation
Expand All @@ -58,7 +68,7 @@ def process_successful_password_creation
end

def password_form
@password_form ||= PasswordForm.new(@user)
@password_form ||= PasswordForm.new(@user, validate_confirmation: true)
end

def process_unsuccessful_password_creation
Expand Down
9 changes: 5 additions & 4 deletions app/forms/password_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ class PasswordForm
include ActiveModel::Model
include FormPasswordValidator

def initialize(user)
def initialize(user, options = {})
@user = user
@validate_confirmation = options.fetch(:validate_confirmation, false)
end

def submit(params)
submitted_password = params[:password]
@password = params[:password]
@password_confirmation = params[:password_confirmation]
@request_id = params.fetch(:request_id, '')

self.password = submitted_password
@confirmation_enabled = params[:confirmation_enabled].presence

FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes)
end
Expand Down
33 changes: 33 additions & 0 deletions app/javascript/packages/password-confirmation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# `@18f/password-confirmation`

Custom element implementation that adds password inputs with validation for confirmation.

## Usage

Importing the element will register the `<lg-password-confirmation>` custom element:

```ts
import '@18f/password-confirmation/password-confirmation-element';
```

The custom element will implement the behavior for validation, but all markup must already exist.

```html
<lg-password-confirmation>
<label for="input-1">Password</label>
<input id="input-1" class="password-confirmation__input">
<label for="input-1b">Confirm password</label>
<input id="input-1b" class="password-confirmation__input-confirmation">
<div class="password-confirmation__toggle-wrapper">
<input
id="toggle-1"
type="checkbox"
class="password-confirmation__toggle"
aria-controls="input-1"
>
<label for="toggle-1" class="usa-checkbox__label password-confirmation__toggle-label">
Show password
</label>
</div>`;
</lg-password-confirmation>
```
5 changes: 5 additions & 0 deletions app/javascript/packages/password-confirmation/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@18f/identity-password-confirmation",
"private": true,
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import userEvent from '@testing-library/user-event';
import { getByLabelText, waitFor } from '@testing-library/dom';
import { useSandbox } from '@18f/identity-test-helpers';
import * as analytics from '@18f/identity-analytics';
import './password-confirmation-element';
import type PasswordConfirmationElement from './password-confirmation-element';

describe('PasswordConfirmationElement', () => {
let element: PasswordConfirmationElement;
let input1: HTMLInputElement;
let input2: HTMLInputElement;
let idCounter = 0;
const sandbox = useSandbox();

function createElement() {
element = document.createElement('lg-password-confirmation') as PasswordConfirmationElement;
const idSuffix = ++idCounter;
element.innerHTML = `
<label for="input-${idSuffix}">Password</label>
<input id="input-${idSuffix}" class="password-confirmation__input">
<label for="input-${idSuffix}b">Confirm password</label>
<input id="input-${idSuffix}b" class="password-confirmation__input-confirmation">
<div class="password-confirmation__toggle-wrapper">
<input
id="toggle-${idSuffix}"
type="checkbox"
class="password-confirmation__toggle"
aria-controls="input-${idSuffix}"
>
<label for="toggle-${idSuffix}" class="usa-checkbox__label password-confirmation__toggle-label">
Show password
</label>
</div>`;
document.body.appendChild(element);
return element;
}

beforeEach(() => {
element = createElement();
input1 = getByLabelText(element, 'Password') as HTMLInputElement;
input2 = getByLabelText(element, 'Confirm password') as HTMLInputElement;
});

it('initializes input type', () => {
expect(input1.type).to.equal('password');
});

it('changes input type on toggle', async () => {
const toggle = getByLabelText(element, 'Show password') as HTMLInputElement;

await userEvent.click(toggle);

expect(input1.type).to.equal('text');
});

it('logs an event when clicking the Show Password button', async () => {
sandbox.stub(analytics, 'trackEvent');
const toggle = getByLabelText(element, 'Show password') as HTMLInputElement;

await userEvent.click(toggle);

expect(analytics.trackEvent).to.have.been.calledWith('Show Password button clicked', {
path: window.location.pathname,
});
});

describe('Password validation', () => {
it('validates passwords in both directions', async () => {
await userEvent.type(input1, 'salty pickles');
await userEvent.type(input2, 'salty pickles2');
await waitFor(() => {
expect(input2.checkValidity()).to.be.false();
});

await userEvent.clear(input1);
await userEvent.type(input1, 'salty pickles2');
await waitFor(() => {
expect(input2.checkValidity()).to.be.true();
});

await userEvent.clear(input1);
await userEvent.type(input1, 'salty pickles3');
await waitFor(() => {
expect(input2.checkValidity()).to.be.false();
});

await userEvent.clear(input2);
await userEvent.type(input2, 'salty pickles3');
await waitFor(() => {
expect(input2.checkValidity()).to.be.true();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { trackEvent } from '@18f/identity-analytics';
import { t } from '@18f/identity-i18n';

class PasswordConfirmationElement extends HTMLElement {
connectedCallback() {
this.toggle.addEventListener('change', () => this.setInputType());
this.toggle.addEventListener('click', () => this.trackToggleEvent());
this.input.addEventListener('input', () => this.validatePassword());
this.inputConfirmation.addEventListener('input', () => this.validatePassword());
this.setInputType();
}

/**
* Checkbox toggle for visibility.
*/
get toggle(): HTMLInputElement {
return this.querySelector('.password-confirmation__toggle')! as HTMLInputElement;
}

/**
* Password input.
*/
get input(): HTMLInputElement {
return this.querySelector('.password-confirmation__input')! as HTMLInputElement;
}

/**
* Password confirmation input.
*/
get inputConfirmation(): HTMLInputElement {
return this.querySelector('.password-confirmation__input-confirmation')! as HTMLInputElement;
}

setInputType() {
const checked = this.toggle.checked ? 'text' : 'password';
this.input.type = checked;
this.inputConfirmation.type = checked;
}

trackToggleEvent() {
trackEvent('Show Password button clicked', { path: window.location.pathname });
}

validatePassword() {
const password = this.input.value;
const confirmation = this.inputConfirmation.value;

if (password && password !== confirmation) {
const errorMsg = t('components.password_confirmation.errors.mismatch');
this.inputConfirmation.setCustomValidity(errorMsg);
} else {
this.inputConfirmation.setCustomValidity('');
}
}
}

declare global {
interface HTMLElementTagNameMap {
'lg-password-confirmation': PasswordConfirmationElement;
}
}

if (!customElements.get('lg-password-confirmation')) {
customElements.define('lg-password-confirmation', PasswordConfirmationElement);
}

export default PasswordConfirmationElement;
10 changes: 1 addition & 9 deletions app/javascript/packages/password-toggle/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
{
"name": "@18f/identity-password-toggle",
"private": true,
"version": "1.0.0",
"peerDependencies": {
"react": "^17.0.2"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
}
"version": "1.0.0"
}
Loading