Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

10353 Bug: Duplicate Cognito Accounts #5252

Merged
merged 11 commits into from
Aug 23, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,37 @@ describe('Petitioner Account Creation', () => {
});

describe('Create Petitioner Account and login', () => {
const TEST_EMAIL = `cypress_test_account+success_${GUID}@example.com`;
const TEST_NAME = 'Cypress Test';
const TEST_PASSWORD = generatePassword(VALID_PASSWORD_CONFIG);

it('should create an account and verify it using the verification link, then login and create an eletronic case', () => {
it('should prevent multiple submissions', () => {
const TEST_EMAIL = `cypress_test_account+no_multiple_submissions_${GUID}@example.com`;
cy.visit('/create-account/petitioner');
cy.get('[data-testid="petitioner-account-creation-email"]').type(
TEST_EMAIL,
);
cy.get('[data-testid="petitioner-account-creation-name"]').type(
TEST_NAME,
);
cy.get('[data-testid="petitioner-account-creation-password"]').type(
TEST_PASSWORD,
);
cy.get(
'[data-testid="petitioner-account-creation-confirm-password"]',
).type(TEST_PASSWORD);
cy.intercept('POST', '/auth/account/create').as('accountCreationRequest');

// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.get('[data-testid="petitioner-account-creation-submit-button"]')
.click({ force: true })
.click({ force: true });

cy.wait('@accountCreationRequest');
cy.get('@accountCreationRequest.all').should('have.length', 1);
});

it('should create an account and verify it using the verification link, then login and create an electronic case', () => {
const TEST_EMAIL = `cypress_test_account+success_${GUID}@example.com`;
createAPetitioner({
email: TEST_EMAIL,
name: TEST_NAME,
Expand Down
5 changes: 5 additions & 0 deletions web-api/src/business/useCases/auth/signUpUserInteractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export const signUpUserInteractor = async (
email: user.email,
});

// Note that this check can fail to catch two (nearly) simultaneous requests,
// and Cognito can therefore create accounts with the same email.
// (See https://stackoverflow.com/questions/50730759/user-pool-allows-two-users-with-same-email-despite-configuration)
// On the frontend, we can prevent multiple submissions; if we wanted to enforce non-duplicates on the backend,
// we would probably need to run an asynchronous task to delete duplicate records.
if (existingAccount) {
const accountUnconfirmed =
existingAccount.accountStatus === UserStatusType.UNCONFIRMED;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Button } from '@web-client/ustc-ui/Button/Button';
import { RequirementsText } from '@web-client/views/CreatePetitionerAccount/RequirementsText';
import { connect } from '@web-client/presenter/shared.cerebral';
import { debounce } from 'lodash';
import { sequences, state } from '@web-client/presenter/app.cerebral';
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';

const DEBOUNCE_TIME_MS = 500;

export const CreatePetitionerAccountForm = connect(
{
alertError: state.alertError,
alertWarning: state.alertWarning,
confirmPassword: state.form.confirmPassword,
createAccountHelper: state.createAccountHelper,
navigateToLoginSequence: sequences.navigateToLoginSequence,
Expand All @@ -18,6 +23,8 @@ export const CreatePetitionerAccountForm = connect(
updateFormValueSequence: sequences.updateFormValueSequence,
},
({
alertError,
alertWarning,
confirmPassword,
createAccountHelper,
navigateToLoginSequence,
Expand All @@ -30,6 +37,18 @@ export const CreatePetitionerAccountForm = connect(
}) => {
const [inFocusEmail, setInFocusEmail] = useState(true);
const [inFocusName, setInFocusName] = useState(true);
const [submitDisabled, setSubmitDisabled] = useState(false);

// Re-enabled submit button if submission was unsuccessful
useEffect(() => {
if (alertError || alertWarning) {
setSubmitDisabled(false);
}
}, [alertError, alertWarning]);

const submitFunction = debounce(() => {
submitCreatePetitionerAccountFormSequence();
}, DEBOUNCE_TIME_MS);

return (
<>
Expand All @@ -42,7 +61,8 @@ export const CreatePetitionerAccountForm = connect(
<form
onSubmit={e => {
e.preventDefault();
submitCreatePetitionerAccountFormSequence();
setSubmitDisabled(true);
submitFunction();
}}
>
<label className="usa-label" htmlFor="email">
Expand Down Expand Up @@ -205,7 +225,7 @@ export const CreatePetitionerAccountForm = connect(
<Button
className="usa-button margin-top-2"
data-testid="petitioner-account-creation-submit-button"
disabled={!createAccountHelper.formIsValid}
disabled={!createAccountHelper.formIsValid || submitDisabled}
id="submit-button"
>
Continue
Expand Down
Loading